static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc) { uint32_t dst_ip = msg->content.in_info.in_dst_ip; in_cache_entry *entry; entry = mpc->in_ops->get(dst_ip, mpc); if(entry == NULL){ entry = mpc->in_ops->add_entry(dst_ip, mpc); entry->entry_state = INGRESS_RESOLVING; msg->type = SND_MPOA_RES_RQST; msg->content.in_info = entry->ctrl_info; msg_to_mpoad(msg, mpc); do_gettimeofday(&(entry->reply_wait)); mpc->in_ops->put(entry); return; } if(entry->entry_state == INGRESS_INVALID){ entry->entry_state = INGRESS_RESOLVING; msg->type = SND_MPOA_RES_RQST; msg->content.in_info = entry->ctrl_info; msg_to_mpoad(msg, mpc); do_gettimeofday(&(entry->reply_wait)); mpc->in_ops->put(entry); return; } printk("mpoa: (%s) MPOA_trigger_rcvd: entry already in resolving state\n", (mpc->dev) ? mpc->dev->name : "<unknown>"); mpc->in_ops->put(entry); return; }
/* * Things get complicated because we have to check if there's an egress * shortcut with suitable traffic parameters we could use. */ static void check_qos_and_open_shortcut(struct k_message *msg, struct mpoa_client *client, in_cache_entry *entry) { uint32_t dst_ip = msg->content.in_info.in_dst_ip; struct atm_mpoa_qos *qos = atm_mpoa_search_qos(dst_ip); eg_cache_entry *eg_entry = client->eg_ops->get_by_src_ip(dst_ip, client); if(eg_entry && eg_entry->shortcut){ if(eg_entry->shortcut->qos.txtp.traffic_class & msg->qos.txtp.traffic_class & (qos ? qos->qos.txtp.traffic_class : ATM_UBR | ATM_CBR)){ if(eg_entry->shortcut->qos.txtp.traffic_class == ATM_UBR) entry->shortcut = eg_entry->shortcut; else if(eg_entry->shortcut->qos.txtp.max_pcr > 0) entry->shortcut = eg_entry->shortcut; } if(entry->shortcut){ dprintk("mpoa: (%s) using egress SVC to reach %u.%u.%u.%u\n",client->dev->name, NIPQUAD(dst_ip)); client->eg_ops->put(eg_entry); return; } } if (eg_entry != NULL) client->eg_ops->put(eg_entry); /* No luck in the egress cache we must open an ingress SVC */ msg->type = OPEN_INGRESS_SVC; if (qos && (qos->qos.txtp.traffic_class == msg->qos.txtp.traffic_class)) { msg->qos = qos->qos; printk("mpoa: (%s) trying to get a CBR shortcut\n",client->dev->name); } else memset(&msg->qos,0,sizeof(struct atm_qos)); msg_to_mpoad(msg, client); return; }
static void clear_expired(struct mpoa_client *client) { eg_cache_entry *entry, *next_entry; struct timeval now; struct k_message msg; do_gettimeofday(&now); write_lock_irq(&client->egress_lock); entry = client->eg_cache; while(entry != NULL) { next_entry = entry->next; if((now.tv_sec - entry->tv.tv_sec) > entry->ctrl_info.holding_time) { msg.type = SND_EGRESS_PURGE; msg.content.eg_info = entry->ctrl_info; dprintk("mpoa: mpoa_caches.c: egress_cache: holding time expired, cache_id = %lu.\n",ntohl(entry->ctrl_info.cache_id)); msg_to_mpoad(&msg, client); client->eg_ops->remove_entry(entry, client); } entry = next_entry; } write_unlock_irq(&client->egress_lock); return; }
/* * This should be called with write lock on */ static void eg_cache_remove_entry(eg_cache_entry *entry, struct mpoa_client *client) { struct atm_vcc *vcc; struct k_message msg; vcc = entry->shortcut; dprintk("mpoa: mpoa_caches.c: removing an egress entry.\n"); if (entry->prev != NULL) entry->prev->next = entry->next; else client->eg_cache = entry->next; if (entry->next != NULL) entry->next->prev = entry->prev; client->eg_ops->put(entry); if(client->in_cache == NULL && client->eg_cache == NULL) { msg.type = STOP_KEEP_ALIVE_SM; msg_to_mpoad(&msg,client); } /* Check if the ingress side still uses this VCC */ if (vcc != NULL) { in_cache_entry *in_entry = client->in_ops->get_by_vcc(vcc, client); if (in_entry != NULL) { client->in_ops->put(in_entry); return; } vcc_release_async(vcc, -EPIPE); } return; }
static int cache_hit(in_cache_entry *entry, struct mpoa_client *mpc) { struct atm_mpoa_qos *qos; struct k_message msg; entry->count++; if (entry->entry_state == INGRESS_RESOLVED && entry->shortcut != NULL) return OPEN; if (entry->entry_state == INGRESS_REFRESHING) { if (entry->count > mpc->parameters.mpc_p1) { msg.type = SND_MPOA_RES_RQST; msg.content.in_info = entry->ctrl_info; memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN); qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); if (qos != NULL) msg.qos = qos->qos; msg_to_mpoad(&msg, mpc); do_gettimeofday(&(entry->reply_wait)); entry->entry_state = INGRESS_RESOLVING; } if (entry->shortcut != NULL) return OPEN; return CLOSED; } if (entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL) return OPEN; if (entry->count > mpc->parameters.mpc_p1 && entry->entry_state == INGRESS_INVALID) { dprintk("(%s) threshold exceeded for ip %pI4, sending MPOA res req\n", mpc->dev->name, &entry->ctrl_info.in_dst_ip); entry->entry_state = INGRESS_RESOLVING; msg.type = SND_MPOA_RES_RQST; memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN); msg.content.in_info = entry->ctrl_info; qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); if (qos != NULL) msg.qos = qos->qos; msg_to_mpoad(&msg, mpc); do_gettimeofday(&(entry->reply_wait)); } return CLOSED; }
static void send_set_mps_ctrl_addr(const char *addr, struct mpoa_client *mpc) { struct k_message mesg; memcpy(mpc->mps_ctrl_addr, addr, ATM_ESA_LEN); mesg.type = SET_MPS_CTRL_ADDR; memcpy(mesg.MPS_ctrl, addr, ATM_ESA_LEN); msg_to_mpoad(&mesg, mpc); }
/* * purge egress cache and tell daemon to 'action' (DIE, RELOAD) */ static void clean_up(struct k_message *msg, struct mpoa_client *mpc, int action) { eg_cache_entry *entry; msg->type = SND_EGRESS_PURGE; /* FIXME: This knows too much of the cache structure */ read_lock_irq(&mpc->egress_lock); entry = mpc->eg_cache; while (entry != NULL) { msg->content.eg_info = entry->ctrl_info; dprintk("cache_id %u\n", entry->ctrl_info.cache_id); msg_to_mpoad(msg, mpc); entry = entry->next; } read_unlock_irq(&mpc->egress_lock); msg->type = action; msg_to_mpoad(msg, mpc); }
/* Call this every MPC-p4 seconds. */ static void check_resolving_entries(struct mpoa_client *client) { struct atm_mpoa_qos *qos; in_cache_entry *entry; struct timeval now; struct k_message msg; do_gettimeofday(&now); read_lock_bh(&client->ingress_lock); entry = client->in_cache; while (entry != NULL) { if (entry->entry_state == INGRESS_RESOLVING) { if ((now.tv_sec - entry->hold_down.tv_sec) < client->parameters.mpc_p6) { entry = entry->next; /* Entry in hold down */ continue; } if ((now.tv_sec - entry->reply_wait.tv_sec) > entry->retry_time) { entry->retry_time = MPC_C1 * (entry->retry_time); /* * Retry time maximum exceeded, * put entry in hold down. */ if (entry->retry_time > client->parameters.mpc_p5) { do_gettimeofday(&(entry->hold_down)); entry->retry_time = client->parameters.mpc_p4; entry = entry->next; continue; } /* Ask daemon to send a resolution request. */ memset(&(entry->hold_down), 0, sizeof(struct timeval)); msg.type = SND_MPOA_RES_RTRY; memcpy(msg.MPS_ctrl, client->mps_ctrl_addr, ATM_ESA_LEN); msg.content.in_info = entry->ctrl_info; qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); if (qos != NULL) msg.qos = qos->qos; msg_to_mpoad(&msg, client); do_gettimeofday(&(entry->reply_wait)); } } entry = entry->next; } read_unlock_bh(&client->ingress_lock); }