| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| #include "router_core_private.h" |
| #include "route_control.h" |
| #include <stdio.h> |
| |
| static void qdr_add_router_CT (qdr_core_t *core, qdr_action_t *action, bool discard); |
| static void qdr_del_router_CT (qdr_core_t *core, qdr_action_t *action, bool discard); |
| static void qdr_set_link_CT (qdr_core_t *core, qdr_action_t *action, bool discard); |
| static void qdr_remove_link_CT (qdr_core_t *core, qdr_action_t *action, bool discard); |
| static void qdr_set_next_hop_CT (qdr_core_t *core, qdr_action_t *action, bool discard); |
| static void qdr_remove_next_hop_CT (qdr_core_t *core, qdr_action_t *action, bool discard); |
| static void qdr_set_cost_CT (qdr_core_t *core, qdr_action_t *action, bool discard); |
| static void qdr_set_valid_origins_CT (qdr_core_t *core, qdr_action_t *action, bool discard); |
| static void qdr_flush_destinations_CT (qdr_core_t *core, qdr_action_t *action, bool discard); |
| static void qdr_mobile_seq_advanced_CT (qdr_core_t *core, qdr_action_t *action, bool discard); |
| static void qdr_subscribe_CT (qdr_core_t *core, qdr_action_t *action, bool discard); |
| static void qdr_unsubscribe_CT (qdr_core_t *core, qdr_action_t *action, bool discard); |
| |
| |
| //================================================================================== |
| // Interface Functions |
| //================================================================================== |
| |
| void qdr_core_add_router(qdr_core_t *core, const char *address, int router_maskbit) |
| { |
| qdr_action_t *action = qdr_action(qdr_add_router_CT, "add_router"); |
| action->args.route_table.router_maskbit = router_maskbit; |
| action->args.route_table.address = qdr_field(address); |
| qdr_action_enqueue(core, action); |
| } |
| |
| |
| void qdr_core_del_router(qdr_core_t *core, int router_maskbit) |
| { |
| qdr_action_t *action = qdr_action(qdr_del_router_CT, "del_router"); |
| action->args.route_table.router_maskbit = router_maskbit; |
| qdr_action_enqueue(core, action); |
| } |
| |
| |
| void qdr_core_set_link(qdr_core_t *core, int router_maskbit, int link_maskbit) |
| { |
| qdr_action_t *action = qdr_action(qdr_set_link_CT, "set_link"); |
| action->args.route_table.router_maskbit = router_maskbit; |
| action->args.route_table.link_maskbit = link_maskbit; |
| qdr_action_enqueue(core, action); |
| } |
| |
| |
| void qdr_core_remove_link(qdr_core_t *core, int router_maskbit) |
| { |
| qdr_action_t *action = qdr_action(qdr_remove_link_CT, "remove_link"); |
| action->args.route_table.router_maskbit = router_maskbit; |
| qdr_action_enqueue(core, action); |
| } |
| |
| |
| void qdr_core_set_next_hop(qdr_core_t *core, int router_maskbit, int nh_router_maskbit) |
| { |
| qdr_action_t *action = qdr_action(qdr_set_next_hop_CT, "set_next_hop"); |
| action->args.route_table.router_maskbit = router_maskbit; |
| action->args.route_table.nh_router_maskbit = nh_router_maskbit; |
| qdr_action_enqueue(core, action); |
| } |
| |
| |
| void qdr_core_remove_next_hop(qdr_core_t *core, int router_maskbit) |
| { |
| qdr_action_t *action = qdr_action(qdr_remove_next_hop_CT, "remove_next_hop"); |
| action->args.route_table.router_maskbit = router_maskbit; |
| qdr_action_enqueue(core, action); |
| } |
| |
| |
| void qdr_core_set_cost(qdr_core_t *core, int router_maskbit, int cost) |
| { |
| qdr_action_t *action = qdr_action(qdr_set_cost_CT, "set_cost"); |
| action->args.route_table.router_maskbit = router_maskbit; |
| action->args.route_table.cost = cost; |
| qdr_action_enqueue(core, action); |
| } |
| |
| |
| void qdr_core_set_valid_origins(qdr_core_t *core, int router_maskbit, qd_bitmask_t *routers) |
| { |
| qdr_action_t *action = qdr_action(qdr_set_valid_origins_CT, "set_valid_origins"); |
| action->args.route_table.router_maskbit = router_maskbit; |
| action->args.route_table.router_set = routers; |
| qdr_action_enqueue(core, action); |
| } |
| |
| |
| void qdr_core_flush_destinations(qdr_core_t *core, int router_maskbit) |
| { |
| qdr_action_t *action = qdr_action(qdr_flush_destinations_CT, "flush_destinations"); |
| action->args.route_table.router_maskbit = router_maskbit; |
| qdr_action_enqueue(core, action); |
| } |
| |
| |
| void qdr_core_mobile_seq_advanced(qdr_core_t *core, int router_maskbit) |
| { |
| qdr_action_t *action = qdr_action(qdr_mobile_seq_advanced_CT, "mobile_seq_advanced"); |
| action->args.route_table.router_maskbit = router_maskbit; |
| qdr_action_enqueue(core, action); |
| } |
| |
| |
| void qdr_core_route_table_handlers(qdr_core_t *core, |
| void *context, |
| qdr_set_mobile_seq_t set_mobile_seq, |
| qdr_set_my_mobile_seq_t set_my_mobile_seq, |
| qdr_link_lost_t link_lost) |
| { |
| core->rt_context = context; |
| core->rt_set_mobile_seq = set_mobile_seq; |
| core->rt_set_my_mobile_seq = set_my_mobile_seq; |
| core->rt_link_lost = link_lost; |
| } |
| |
| |
| qdr_subscription_t *qdr_core_subscribe(qdr_core_t *core, |
| const char *address, |
| char aclass, |
| char phase, |
| qd_address_treatment_t treatment, |
| bool in_core, |
| qdr_receive_t on_message, |
| void *context) |
| { |
| qdr_subscription_t *sub = NEW(qdr_subscription_t); |
| sub->core = core; |
| sub->addr = 0; |
| sub->on_message = on_message; |
| sub->on_message_context = context; |
| sub->in_core = in_core; |
| |
| qdr_action_t *action = qdr_action(qdr_subscribe_CT, "subscribe"); |
| action->args.io.address = qdr_field(address); |
| action->args.io.address_class = aclass; |
| action->args.io.address_phase = phase; |
| action->args.io.subscription = sub; |
| action->args.io.treatment = treatment; |
| qdr_action_enqueue(core, action); |
| |
| return sub; |
| } |
| |
| |
| void qdr_core_unsubscribe(qdr_subscription_t *sub) |
| { |
| if (sub) { |
| qdr_action_t *action = qdr_action(qdr_unsubscribe_CT, "unsubscribe"); |
| action->args.io.subscription = sub; |
| qdr_action_enqueue(sub->core, action); |
| } |
| } |
| |
| |
| //================================================================================== |
| // In-Thread Functions |
| //================================================================================== |
| |
| // |
| // React to the updated cost of a router node. The core->routers list is to be kept |
| // sorted by cost, from least to most. |
| // |
| void qdr_route_table_update_cost_CT(qdr_core_t *core, qdr_node_t *rnode) |
| { |
| qdr_node_t *ptr; |
| bool needs_reinsertion = false; |
| |
| ptr = DEQ_PREV(rnode); |
| if (ptr && ptr->cost > rnode->cost) |
| needs_reinsertion = true; |
| else { |
| ptr = DEQ_NEXT(rnode); |
| if (ptr && ptr->cost < rnode->cost) |
| needs_reinsertion = true; |
| } |
| |
| if (needs_reinsertion) { |
| core->cost_epoch++; |
| DEQ_REMOVE(core->routers, rnode); |
| ptr = DEQ_TAIL(core->routers); |
| while (ptr) { |
| if (rnode->cost >= ptr->cost) { |
| DEQ_INSERT_AFTER(core->routers, rnode, ptr); |
| break; |
| } |
| ptr = DEQ_PREV(ptr); |
| } |
| |
| if (!ptr) |
| DEQ_INSERT_HEAD(core->routers, rnode); |
| } |
| } |
| |
| |
| void qdr_route_table_setup_CT(qdr_core_t *core) |
| { |
| DEQ_INIT(core->addrs); |
| DEQ_INIT(core->routers); |
| core->addr_hash = qd_hash(12, 32, 0); |
| core->conn_id_hash = qd_hash(6, 4, 0); |
| core->cost_epoch = 1; |
| core->addr_parse_tree = qd_parse_tree_new(QD_PARSE_TREE_ADDRESS); |
| core->link_route_tree[QD_INCOMING] = qd_parse_tree_new(QD_PARSE_TREE_ADDRESS); |
| core->link_route_tree[QD_OUTGOING] = qd_parse_tree_new(QD_PARSE_TREE_ADDRESS); |
| |
| if (core->router_mode == QD_ROUTER_MODE_INTERIOR) { |
| core->hello_addr = qdr_add_local_address_CT(core, 'L', "qdhello", QD_TREATMENT_MULTICAST_FLOOD); |
| core->router_addr_L = qdr_add_local_address_CT(core, 'L', "qdrouter", QD_TREATMENT_MULTICAST_FLOOD); |
| core->routerma_addr_L = qdr_add_local_address_CT(core, 'L', "qdrouter.ma", QD_TREATMENT_MULTICAST_ONCE); |
| core->router_addr_T = qdr_add_local_address_CT(core, 'T', "qdrouter", QD_TREATMENT_MULTICAST_FLOOD); |
| core->routerma_addr_T = qdr_add_local_address_CT(core, 'T', "qdrouter.ma", QD_TREATMENT_MULTICAST_ONCE); |
| |
| core->hello_addr->router_control_only = true; |
| core->router_addr_L->router_control_only = true; |
| core->routerma_addr_L->router_control_only = true; |
| core->router_addr_T->router_control_only = true; |
| core->routerma_addr_T->router_control_only = true; |
| |
| core->neighbor_free_mask = qd_bitmask(1); |
| |
| core->routers_by_mask_bit = NEW_PTR_ARRAY(qdr_node_t, qd_bitmask_width()); |
| core->control_links_by_mask_bit = NEW_PTR_ARRAY(qdr_link_t, qd_bitmask_width()); |
| core->data_links_by_mask_bit = NEW_ARRAY(qdr_priority_sheaf_t, qd_bitmask_width()); |
| for (int idx = 0; idx < qd_bitmask_width(); idx++) { |
| core->routers_by_mask_bit[idx] = 0; |
| core->control_links_by_mask_bit[idx] = 0; |
| core->data_links_by_mask_bit[idx].count = 0; |
| for (int priority = 0; priority < QDR_N_PRIORITIES; ++ priority) |
| core->data_links_by_mask_bit[idx].links[priority] = 0; |
| |
| } |
| } |
| } |
| |
| |
| static void qdr_add_router_CT(qdr_core_t *core, qdr_action_t *action, bool discard) |
| { |
| int router_maskbit = action->args.route_table.router_maskbit; |
| qdr_field_t *address = action->args.route_table.address; |
| |
| if (discard) { |
| qdr_field_free(address); |
| return; |
| } |
| |
| do { |
| if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { |
| qd_log(core->log, QD_LOG_CRITICAL, "add_router: Router maskbit out of range: %d", router_maskbit); |
| break; |
| } |
| |
| if (core->routers_by_mask_bit[router_maskbit] != 0) { |
| qd_log(core->log, QD_LOG_CRITICAL, "add_router: Router maskbit already in use: %d", router_maskbit); |
| break; |
| } |
| |
| // |
| // Hash lookup the address to ensure there isn't an existing router address. |
| // |
| qd_iterator_t *iter = address->iterator; |
| qdr_address_t *addr; |
| |
| qd_iterator_reset_view(iter, ITER_VIEW_ADDRESS_HASH); |
| qd_hash_retrieve(core->addr_hash, iter, (void**) &addr); |
| |
| if (!addr) { |
| // |
| // Create an address record for this router and insert it in the hash table. |
| // This record will be found whenever a "foreign" topological address to this |
| // remote router is looked up. |
| // |
| addr = qdr_address_CT(core, QD_TREATMENT_ANYCAST_CLOSEST, 0); |
| qd_hash_insert(core->addr_hash, iter, addr, &addr->hash_handle); |
| DEQ_INSERT_TAIL(core->addrs, addr); |
| } |
| |
| // |
| // Bump the address's ref_count for the time that it is associated with an existing remote router node. |
| // |
| addr->ref_count++; |
| |
| // |
| // Create a router-node record to represent the remote router. |
| // |
| qdr_node_t *rnode = new_qdr_node_t(); |
| ZERO(rnode); |
| rnode->owning_addr = addr; |
| rnode->mask_bit = router_maskbit; |
| rnode->link_mask_bit = -1; |
| rnode->valid_origins = qd_bitmask(0); |
| |
| qd_iterator_reset_view(iter, ITER_VIEW_ALL); |
| int addr_len = qd_iterator_length(iter); |
| |
| rnode->wire_address_ma = (char*) malloc(addr_len + 4); |
| qd_iterator_ncopy(iter, (unsigned char*) rnode->wire_address_ma, addr_len); |
| strcpy(rnode->wire_address_ma + addr_len, ".ma"); |
| |
| // |
| // Insert at the head of the list because we don't yet know the cost to this |
| // router node and we've set the cost to zero. This puts it in a properly-sorted |
| // position. Also, don't bump the cost_epoch here because this new router won't be |
| // used until it is assigned a cost. |
| // |
| DEQ_INSERT_HEAD(core->routers, rnode); |
| |
| // |
| // Link the router record to the address record. |
| // |
| qd_bitmask_set_bit(addr->rnodes, router_maskbit); |
| |
| // |
| // Link the router record to the router address records. |
| // Use the T-class addresses only. |
| // |
| qd_bitmask_set_bit(core->router_addr_T->rnodes, router_maskbit); |
| qd_bitmask_set_bit(core->routerma_addr_T->rnodes, router_maskbit); |
| |
| // |
| // Bump the ref-count by three for each of the above links. |
| // |
| rnode->ref_count += 3; |
| |
| // |
| // Add the router record to the mask-bit index. |
| // |
| core->routers_by_mask_bit[router_maskbit] = rnode; |
| } while (false); |
| |
| qdr_field_free(address); |
| } |
| |
| |
| static void qdr_del_router_CT(qdr_core_t *core, qdr_action_t *action, bool discard) |
| { |
| int router_maskbit = action->args.route_table.router_maskbit; |
| |
| if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { |
| qd_log(core->log, QD_LOG_CRITICAL, "del_router: Router maskbit out of range: %d", router_maskbit); |
| return; |
| } |
| |
| if (core->routers_by_mask_bit[router_maskbit] == 0) { |
| qd_log(core->log, QD_LOG_CRITICAL, "del_router: Deleting nonexistent router: %d", router_maskbit); |
| return; |
| } |
| |
| qdr_node_t *rnode = core->routers_by_mask_bit[router_maskbit]; |
| qdr_address_t *oaddr = rnode->owning_addr; |
| assert(oaddr); |
| |
| // |
| // Unlink the router node from the address record |
| // |
| qd_bitmask_clear_bit(oaddr->rnodes, router_maskbit); |
| qd_bitmask_clear_bit(core->router_addr_T->rnodes, router_maskbit); |
| qd_bitmask_clear_bit(core->routerma_addr_T->rnodes, router_maskbit); |
| rnode->ref_count -= 3; |
| |
| // |
| // While the router node has a non-zero reference count, look for addresses |
| // to unlink the node from. |
| // |
| qdr_address_t *addr = DEQ_HEAD(core->addrs); |
| while (addr && rnode->ref_count > 0) { |
| if (qd_bitmask_clear_bit(addr->rnodes, router_maskbit)) |
| // |
| // If the cleared bit was originally set, decrement the ref count |
| // |
| rnode->ref_count--; |
| addr = DEQ_NEXT(addr); |
| } |
| assert(rnode->ref_count == 0); |
| |
| // |
| // Free the router node. |
| // |
| qdr_router_node_free(core, rnode); |
| |
| // |
| // Check the address and free it if there are no other interested parties tracking it |
| // |
| oaddr->ref_count--; |
| qdr_check_addr_CT(core, oaddr); |
| } |
| |
| |
| static void qdr_set_link_CT(qdr_core_t *core, qdr_action_t *action, bool discard) |
| { |
| int router_maskbit = action->args.route_table.router_maskbit; |
| int link_maskbit = action->args.route_table.link_maskbit; |
| |
| if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { |
| qd_log(core->log, QD_LOG_CRITICAL, "set_link: Router maskbit out of range: %d", router_maskbit); |
| return; |
| } |
| |
| if (link_maskbit >= qd_bitmask_width() || link_maskbit < 0) { |
| qd_log(core->log, QD_LOG_CRITICAL, "set_link: Link maskbit out of range: %d", link_maskbit); |
| return; |
| } |
| |
| if (core->control_links_by_mask_bit[link_maskbit] == 0) { |
| qd_log(core->log, QD_LOG_CRITICAL, "set_link: Invalid link reference: %d", link_maskbit); |
| return; |
| } |
| |
| if (core->routers_by_mask_bit[router_maskbit] == 0) { |
| qd_log(core->log, QD_LOG_CRITICAL, "set_link: Router not found"); |
| return; |
| } |
| |
| // |
| // Add the peer_link reference to the router record. |
| // |
| qdr_node_t *rnode = core->routers_by_mask_bit[router_maskbit]; |
| rnode->link_mask_bit = link_maskbit; |
| qdr_addr_start_inlinks_CT(core, rnode->owning_addr); |
| } |
| |
| |
| static void qdr_remove_link_CT(qdr_core_t *core, qdr_action_t *action, bool discard) |
| { |
| int router_maskbit = action->args.route_table.router_maskbit; |
| |
| if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { |
| qd_log(core->log, QD_LOG_CRITICAL, "remove_link: Router maskbit out of range: %d", router_maskbit); |
| return; |
| } |
| |
| if (core->routers_by_mask_bit[router_maskbit] == 0) { |
| qd_log(core->log, QD_LOG_CRITICAL, "remove_link: Router not found"); |
| return; |
| } |
| |
| qdr_node_t *rnode = core->routers_by_mask_bit[router_maskbit]; |
| rnode->link_mask_bit = -1; |
| } |
| |
| |
| static void qdr_set_next_hop_CT(qdr_core_t *core, qdr_action_t *action, bool discard) |
| { |
| int router_maskbit = action->args.route_table.router_maskbit; |
| int nh_router_maskbit = action->args.route_table.nh_router_maskbit; |
| |
| if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { |
| qd_log(core->log, QD_LOG_CRITICAL, "set_next_hop: Router maskbit out of range: %d", router_maskbit); |
| return; |
| } |
| |
| if (nh_router_maskbit >= qd_bitmask_width() || nh_router_maskbit < 0) { |
| qd_log(core->log, QD_LOG_CRITICAL, "set_next_hop: Next hop router maskbit out of range: %d", router_maskbit); |
| return; |
| } |
| |
| if (core->routers_by_mask_bit[router_maskbit] == 0) { |
| qd_log(core->log, QD_LOG_CRITICAL, "set_next_hop: Router not found"); |
| return; |
| } |
| |
| if (core->routers_by_mask_bit[nh_router_maskbit] == 0) { |
| qd_log(core->log, QD_LOG_CRITICAL, "set_next_hop: Next hop router not found"); |
| return; |
| } |
| |
| if (router_maskbit != nh_router_maskbit) { |
| qdr_node_t *rnode = core->routers_by_mask_bit[router_maskbit]; |
| rnode->next_hop = core->routers_by_mask_bit[nh_router_maskbit]; |
| qdr_addr_start_inlinks_CT(core, rnode->owning_addr); |
| } |
| } |
| |
| |
| static void qdr_remove_next_hop_CT(qdr_core_t *core, qdr_action_t *action, bool discard) |
| { |
| int router_maskbit = action->args.route_table.router_maskbit; |
| |
| if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { |
| qd_log(core->log, QD_LOG_CRITICAL, "remove_next_hop: Router maskbit out of range: %d", router_maskbit); |
| return; |
| } |
| |
| qdr_node_t *rnode = core->routers_by_mask_bit[router_maskbit]; |
| rnode->next_hop = 0; |
| } |
| |
| |
| static void qdr_set_cost_CT(qdr_core_t *core, qdr_action_t *action, bool discard) |
| { |
| int router_maskbit = action->args.route_table.router_maskbit; |
| int cost = action->args.route_table.cost; |
| |
| if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { |
| qd_log(core->log, QD_LOG_CRITICAL, "set_cost: Router maskbit out of range: %d", router_maskbit); |
| return; |
| } |
| |
| if (cost < 1) { |
| qd_log(core->log, QD_LOG_CRITICAL, "set_cost: Invalid cost %d for maskbit: %d", cost, router_maskbit); |
| return; |
| } |
| |
| qdr_node_t *rnode = core->routers_by_mask_bit[router_maskbit]; |
| rnode->cost = cost; |
| qdr_route_table_update_cost_CT(core, rnode); |
| } |
| |
| |
| static void qdr_set_valid_origins_CT(qdr_core_t *core, qdr_action_t *action, bool discard) |
| { |
| int router_maskbit = action->args.route_table.router_maskbit; |
| qd_bitmask_t *valid_origins = action->args.route_table.router_set; |
| |
| if (discard) { |
| qd_bitmask_free(valid_origins); |
| return; |
| } |
| |
| do { |
| if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { |
| qd_log(core->log, QD_LOG_CRITICAL, "set_valid_origins: Router maskbit out of range: %d", router_maskbit); |
| break; |
| } |
| |
| if (core->routers_by_mask_bit[router_maskbit] == 0) { |
| qd_log(core->log, QD_LOG_CRITICAL, "set_valid_origins: Router not found"); |
| break; |
| } |
| |
| qdr_node_t *rnode = core->routers_by_mask_bit[router_maskbit]; |
| if (rnode->valid_origins) |
| qd_bitmask_free(rnode->valid_origins); |
| rnode->valid_origins = valid_origins; |
| valid_origins = 0; |
| } while (false); |
| |
| if (valid_origins) |
| qd_bitmask_free(valid_origins); |
| } |
| |
| |
| static void qdr_flush_destinations_CT(qdr_core_t *core, qdr_action_t *action, bool discard) |
| { |
| if (!!discard) |
| return; |
| |
| int router_maskbit = action->args.route_table.router_maskbit; |
| |
| do { |
| if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { |
| qd_log(core->log, QD_LOG_CRITICAL, "flush_destinations: Router maskbit out of range: %d", router_maskbit); |
| break; |
| } |
| |
| qdr_node_t *rnode = core->routers_by_mask_bit[router_maskbit]; |
| if (rnode == 0) { |
| qd_log(core->log, QD_LOG_CRITICAL, "flush_destinations: Router not found"); |
| break; |
| } |
| |
| // |
| // Raise the event to be picked up by core modules. |
| // |
| qdrc_event_router_raise(core, QDRC_EVENT_ROUTER_MOBILE_FLUSH, rnode); |
| } while (false); |
| } |
| |
| |
| static void qdr_mobile_seq_advanced_CT(qdr_core_t *core, qdr_action_t *action, bool discard) |
| { |
| if (!!discard) |
| return; |
| |
| int router_maskbit = action->args.route_table.router_maskbit; |
| |
| do { |
| if (router_maskbit >= qd_bitmask_width() || router_maskbit < 0) { |
| qd_log(core->log, QD_LOG_CRITICAL, "seq_advanced: Router maskbit out of range: %d", router_maskbit); |
| break; |
| } |
| |
| qdr_node_t *rnode = core->routers_by_mask_bit[router_maskbit]; |
| if (rnode == 0) { |
| qd_log(core->log, QD_LOG_CRITICAL, "seq_advanced: Router not found"); |
| break; |
| } |
| |
| // |
| // Raise the event to be picked up by core modules. |
| // |
| qdrc_event_router_raise(core, QDRC_EVENT_ROUTER_MOBILE_SEQ_ADVANCED, rnode); |
| } while (false); |
| } |
| |
| |
| static void qdr_subscribe_CT(qdr_core_t *core, qdr_action_t *action, bool discard) |
| { |
| qdr_field_t *address = action->args.io.address; |
| qdr_subscription_t *sub = action->args.io.subscription; |
| |
| if (!discard) { |
| char aclass = action->args.io.address_class; |
| char phase = action->args.io.address_phase; |
| qdr_address_t *addr = 0; |
| |
| char *astring = (char*) qd_iterator_copy(address->iterator); |
| qd_log(core->log, QD_LOG_INFO, "In-process subscription %c/%s", aclass, astring); |
| free(astring); |
| |
| qd_iterator_annotate_prefix(address->iterator, aclass); |
| if (aclass == 'M') |
| qd_iterator_annotate_phase(address->iterator, phase); |
| qd_iterator_reset_view(address->iterator, ITER_VIEW_ADDRESS_HASH); |
| |
| qd_hash_retrieve(core->addr_hash, address->iterator, (void**) &addr); |
| if (!addr) { |
| addr = qdr_address_CT(core, action->args.io.treatment, 0); |
| if (addr) { |
| qd_hash_insert(core->addr_hash, address->iterator, addr, &addr->hash_handle); |
| DEQ_ITEM_INIT(addr); |
| DEQ_INSERT_TAIL(core->addrs, addr); |
| } |
| } |
| if (addr) { |
| sub->addr = addr; |
| DEQ_ITEM_INIT(sub); |
| DEQ_INSERT_TAIL(addr->subscriptions, sub); |
| qdr_addr_start_inlinks_CT(core, addr); |
| } |
| } else |
| free(sub); |
| |
| qdr_field_free(address); |
| } |
| |
| |
| static void qdr_unsubscribe_CT(qdr_core_t *core, qdr_action_t *action, bool discard) |
| { |
| qdr_subscription_t *sub = action->args.io.subscription; |
| |
| if (!discard) { |
| DEQ_REMOVE(sub->addr->subscriptions, sub); |
| sub->addr = 0; |
| qdr_check_addr_CT(sub->core, sub->addr); |
| } |
| |
| free(sub); |
| } |
| |
| //================================================================================== |
| // Call-back Functions |
| //================================================================================== |
| |
| static void qdr_do_set_mobile_seq(qdr_core_t *core, qdr_general_work_t *work) |
| { |
| core->rt_set_mobile_seq(core->rt_context, work->maskbit, work->mobile_seq); |
| } |
| |
| |
| static void qdr_do_set_my_mobile_seq(qdr_core_t *core, qdr_general_work_t *work) |
| { |
| core->rt_set_my_mobile_seq(core->rt_context, work->mobile_seq); |
| } |
| |
| |
| static void qdr_do_link_lost(qdr_core_t *core, qdr_general_work_t *work) |
| { |
| core->rt_link_lost(core->rt_context, work->maskbit); |
| } |
| |
| |
| void qdr_post_set_mobile_seq_CT(qdr_core_t *core, int router_maskbit, uint64_t mobile_seq) |
| { |
| qdr_general_work_t *work = qdr_general_work(qdr_do_set_mobile_seq); |
| work->mobile_seq = mobile_seq; |
| work->maskbit = router_maskbit; |
| qdr_post_general_work_CT(core, work); |
| } |
| |
| |
| void qdr_post_set_my_mobile_seq_CT(qdr_core_t *core, uint64_t mobile_seq) |
| { |
| qdr_general_work_t *work = qdr_general_work(qdr_do_set_my_mobile_seq); |
| work->mobile_seq = mobile_seq; |
| qdr_post_general_work_CT(core, work); |
| } |
| |
| |
| void qdr_post_link_lost_CT(qdr_core_t *core, int link_maskbit) |
| { |
| qdr_general_work_t *work = qdr_general_work(qdr_do_link_lost); |
| work->maskbit = link_maskbit; |
| qdr_post_general_work_CT(core, work); |
| } |
| |
| |