Line data Source code
1 : /* $Id: gmpr_instance.c 346474 2009-11-14 10:18:58Z ssiano $ 2 : * 3 : * gmpr_instance.c - GMP Router-side instance support 4 : * 5 : * Dave Katz, March 2008 6 : * 7 : * Copyright (c) 2008, Juniper Networks, Inc. 8 : * All rights reserved. 9 : */ 10 : #include "gmpx_basic_types.h" 11 : #include "gmp.h" 12 : #include "gmpx_environment.h" 13 : #include "gmp_private.h" 14 : #include "gmp_router.h" 15 : #include "gmpr_private.h" 16 : #include "igmp_protocol.h" 17 : #include "mld_proto.h" 18 : 19 : task_thread gmpr_global_instance_thread; /* Thread of instances */ 20 : 21 : 22 : /* 23 : * gmpr_query_smear_expiry 24 : * 25 : * The query timer smear timer has expired. Smear the query timers and 26 : * restart the smear timer. 27 : */ 28 : static void 29 0 : gmpr_query_smear_expiry (gmpx_timer *timer, void *context) 30 : { 31 : gmpr_instance *instance; 32 : 33 0 : instance = context; 34 : 35 : /* Smear the timers. */ 36 : 37 0 : gmpx_smear_timer_group(instance->rinst_proto, GMP_TIMER_GROUP_GEN_QUERY); 38 : 39 : /* Restart the timer. */ 40 : 41 0 : gmpx_start_timer(timer, GMP_QUERY_SMEAR_IVL, 0); 42 : 43 : /* We're no longer accelerated. */ 44 : 45 0 : instance->rinst_smear_timer_accelerated = FALSE; 46 0 : } 47 : 48 : 49 : /* 50 : * gmpr_accelerate_query_smear 51 : * 52 : * Schedule a smearing of general query timers soon, if this has not already 53 : * been done recently. 54 : */ 55 : void 56 1833 : gmpr_accelerate_query_smear (gmpr_instance *instance) 57 : { 58 : #if 0 59 : /* Do it if it's not already scheduled. */ 60 : 61 : if (!instance->rinst_smear_timer_accelerated) { 62 : gmpx_start_timer(instance->rinst_smear_timer, 63 : GMP_QUERY_QUICK_SMEAR_IVL, 0); 64 : instance->rinst_smear_timer_accelerated = TRUE; 65 : } 66 : #endif 67 1833 : } 68 : 69 : 70 : /* 71 : * gmpr_instance_create 72 : * 73 : * Create a router-side GMP instance. 74 : * 75 : * Returns a pointer to the instance, or NULL if we're out of memory. 76 : */ 77 : gmpr_instance * 78 125 : gmpr_instance_create (gmp_proto proto, void *inst_context) 79 : { 80 : gmpr_instance *instance; 81 : boolean first_instance; 82 : 83 : /* Note if this is the first instance. */ 84 : 85 : first_instance = 86 125 : thread_circular_thread_empty(&gmpr_global_instance_thread); 87 : 88 : /* Allocate the block. */ 89 : 90 125 : instance = gmpx_malloc_block(gmpr_instance_tag); 91 : 92 125 : if (instance) { /* Got one */ 93 : 94 : /* Save the context. */ 95 : 96 125 : instance->rinst_context = inst_context; 97 : 98 : /* Set the protocol type. */ 99 : 100 125 : instance->rinst_proto = proto; 101 : 102 : /* Set the address length and minimum max resp field value. */ 103 : 104 125 : switch (proto) { 105 125 : case GMP_PROTO_IGMP: 106 125 : instance->rinst_addrlen = IPV4_ADDR_LEN; 107 125 : instance->rinst_min_max_resp = IGMP_MAX_RESP_MSEC; 108 125 : break; 109 : 110 0 : case GMP_PROTO_MLD: 111 0 : instance->rinst_addrlen = IPV6_ADDR_LEN; 112 0 : instance->rinst_min_max_resp = MLD_MAX_RESP_MSEC; 113 0 : break; 114 : 115 0 : default: 116 0 : gmpx_assert(FALSE); /* Invalid protocol type! */ 117 : } 118 : 119 : /* Initialize the patricia trees. */ 120 : 121 125 : instance->rinst_intfs = 122 125 : gmpx_patroot_init(sizeof(gmpx_intf_id), 123 : GMPX_PATRICIA_OFFSET(gmpr_intf, 124 : rintf_inst_patnode, 125 : rintf_id)); 126 125 : if (!instance->rinst_intfs) { /* No memory */ 127 0 : gmpx_free_block(gmpr_instance_tag, instance); 128 0 : return NULL; 129 : } 130 125 : instance->rinst_global_state_root = 131 125 : gmpx_patroot_init(instance->rinst_addrlen, 132 : GMPX_PATRICIA_OFFSET(gmpr_global_group, 133 : global_group_node, 134 : global_group_addr)); 135 125 : if (!instance->rinst_global_state_root) { /* No memory */ 136 0 : gmpx_patroot_destroy(instance->rinst_intfs); 137 0 : gmpx_free_block(gmpr_instance_tag, instance); 138 0 : return NULL; 139 : } 140 : 141 : /* Set the magic number and link it into the list. */ 142 : 143 125 : instance->rinst_magic = GMPR_INSTANCE_MAGIC; 144 125 : thread_circular_add_top(&gmpr_global_instance_thread, 145 : &instance->rinst_thread); 146 : 147 : /* Initialize thread heads. */ 148 : 149 125 : thread_new_circular_thread(&instance->rinst_client_thread); 150 125 : thread_new_circular_thread(&instance->rinst_startup_intf_thread); 151 : 152 : /* Create the client ordinal context. */ 153 : 154 125 : instance->rinst_ord_handle = ord_create_context(ORD_COMPACT); 155 125 : if (!instance->rinst_ord_handle) 156 0 : return NULL; /* Out of memory */ 157 : 158 : /* Initialize the address catalog. */ 159 : 160 125 : if (gmp_init_addr_catalog(&instance->rinst_addr_cat, 161 : instance->rinst_addrlen) < 0) { 162 0 : return NULL; /* Out of memory */ 163 : } 164 : 165 : /* Create and start the smear timer. */ 166 : 167 125 : instance->rinst_smear_timer = 168 125 : gmpx_create_timer(instance->rinst_context, "GMP query smear timer", 169 : gmpr_query_smear_expiry, instance); 170 125 : gmpr_accelerate_query_smear(instance); 171 : 172 : /* If this is the first instance, register with the packet handler. */ 173 : 174 125 : if (first_instance) 175 125 : gmpr_register_packet_handler(); 176 : 177 : /* Register the protocol. */ 178 : 179 125 : gmpp_enab_disab_proto(GMP_ROLE_ROUTER, proto, TRUE); 180 : } 181 : 182 125 : return instance; 183 : } 184 : 185 : 186 : /* 187 : * gmpr_get_instance 188 : * 189 : * Return an instance pointer, given an instance ID. 190 : * 191 : * Verifies that the instance ID is valid. 192 : */ 193 : gmpr_instance * 194 8915 : gmpr_get_instance (gmp_instance_id instance_id) 195 : { 196 : gmpr_instance *instance; 197 : 198 : /* Do the (trivial) conversion. */ 199 : 200 8915 : instance = instance_id; 201 : 202 : /* Verify the magic number. */ 203 : 204 8915 : gmpx_assert(instance->rinst_magic == GMPR_INSTANCE_MAGIC); 205 : 206 8915 : return instance; 207 : } 208 : 209 : 210 : /* 211 : * gmpr_instance_destroy 212 : * 213 : * Destroy an instance and all things associated with it. 214 : */ 215 : void 216 125 : gmpr_instance_destroy (gmpr_instance *instance) 217 : { 218 : gmp_proto inst_proto; 219 : task_thread *thread_ptr; 220 : boolean found_proto; 221 : 222 : /* Blast all clients on the instance. */ 223 : 224 125 : gmpr_destroy_instance_clients(instance); 225 : 226 : /* Blast all interfaces on the instance. */ 227 : 228 125 : gmpr_destroy_instance_intfs(instance); 229 : 230 125 : inst_proto = instance->rinst_proto; /* Remember for a bit */ 231 : 232 : /* Make some paranoia checks. */ 233 : 234 125 : gmpx_assert(thread_circular_thread_empty(&instance->rinst_client_thread)); 235 125 : gmpx_assert( 236 : thread_circular_thread_empty(&instance->rinst_startup_intf_thread)); 237 125 : gmpx_assert(!gmpx_patricia_lookup_least(instance->rinst_intfs)); 238 125 : gmpx_assert( 239 : !gmpx_patricia_lookup_least(instance->rinst_global_state_root)); 240 : 241 : /* Toss the trees. */ 242 : 243 125 : gmpx_patroot_destroy(instance->rinst_intfs); 244 125 : gmpx_patroot_destroy(instance->rinst_global_state_root); 245 : 246 : /* Toss the client ordinals. */ 247 : 248 125 : ord_destroy_context(instance->rinst_ord_handle); 249 : 250 : /* Destroy the address catalog. */ 251 : 252 125 : gmp_destroy_addr_catalog(&instance->rinst_addr_cat); 253 : 254 : /* Destroy the smear timer. */ 255 : 256 125 : gmpx_destroy_timer(instance->rinst_smear_timer); 257 : 258 : /* Delink the block and free it. */ 259 : 260 125 : thread_remove(&instance->rinst_thread); 261 125 : gmpx_free_block(gmpr_instance_tag, instance); 262 : 263 : /* If this was the last instance for a protocol, disable it. */ 264 : 265 125 : found_proto = FALSE; 266 125 : FOR_ALL_CIRCULAR_THREAD_ENTRIES(&gmpr_global_instance_thread, thread_ptr) { 267 0 : instance = gmpr_thread_to_instance(thread_ptr); 268 0 : if (instance->rinst_proto == inst_proto) { 269 0 : found_proto = TRUE; 270 0 : break; 271 : } 272 : } 273 125 : if (!found_proto) 274 125 : gmpp_enab_disab_proto(GMP_ROLE_ROUTER, inst_proto, FALSE); 275 : 276 : /* If that was the last instance, deregister with the packet handler. */ 277 : 278 125 : if (thread_circular_thread_empty(&gmpr_global_instance_thread)) 279 125 : gmpp_deregister(GMP_ROLE_ROUTER); 280 125 : }