📄 mpc.c
字号:
stop_mpc(mpc); mpc->dev = NULL; break; case NETDEV_UP: /* the dev was ifconfig'ed up */ mpc = find_mpc_by_lec(dev); if (mpc == NULL) break; if (mpc->mpoad_vcc != NULL) { start_mpc(mpc, dev); } break; case NETDEV_DOWN: /* the dev was ifconfig'ed down */ /* this means that the flow of packets from the * upper layer stops */ mpc = find_mpc_by_lec(dev); if (mpc == NULL) break; if (mpc->mpoad_vcc != NULL) { stop_mpc(mpc); } break; case NETDEV_REBOOT: case NETDEV_CHANGE: case NETDEV_CHANGEMTU: case NETDEV_CHANGEADDR: case NETDEV_GOING_DOWN: break; default: break; } return NOTIFY_DONE;}/* * Functions which are called after a message is received from mpcd. * Msg is reused on purpose. */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; unsigned char *ip __attribute__ ((unused)) = (unsigned char *)&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(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 MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc){ unsigned char *ip; uint32_t dst_ip = msg->content.in_info.in_dst_ip; in_cache_entry *entry = mpc->in_ops->get(dst_ip, mpc); ip = (unsigned char *)&dst_ip; dprintk("mpoa: (%s) MPOA_res_reply_rcvd: ip %u.%u.%u.%u\n", mpc->dev->name, NIPQUAD(ip)); ddprintk("mpoa: (%s) MPOA_res_reply_rcvd() entry = %p", mpc->dev->name, entry); if(entry == NULL){ printk("\nmpoa: (%s) ARGH, received res. reply for an entry that doesn't exist.\n", mpc->dev->name); return; } ddprintk(" entry_state = %d ", entry->entry_state); if (entry->entry_state == INGRESS_RESOLVED) { printk("\nmpoa: (%s) MPOA_res_reply_rcvd for RESOLVED entry!\n", mpc->dev->name); mpc->in_ops->put(entry); return; } entry->ctrl_info = msg->content.in_info; do_gettimeofday(&(entry->tv)); do_gettimeofday(&(entry->reply_wait)); /* Used in refreshing func from now on */ entry->refresh_time = 0; ddprintk("entry->shortcut = %p\n", entry->shortcut); if(entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL){ entry->entry_state = INGRESS_RESOLVED; mpc->in_ops->put(entry); return; /* Shortcut already open... */ } if (entry->shortcut != NULL) { printk("mpoa: (%s) MPOA_res_reply_rcvd: entry->shortcut != NULL, impossible!\n", mpc->dev->name); mpc->in_ops->put(entry); return; } check_qos_and_open_shortcut(msg, mpc, entry); entry->entry_state = INGRESS_RESOLVED; mpc->in_ops->put(entry); return;}static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc){ uint32_t dst_ip = msg->content.in_info.in_dst_ip; uint32_t mask = msg->ip_mask; unsigned char *ip = (unsigned char *)&dst_ip; in_cache_entry *entry = mpc->in_ops->get_with_mask(dst_ip, mpc, mask); if(entry == NULL){ printk("mpoa: (%s) ingress_purge_rcvd: purge for a non-existing entry, ", mpc->dev->name); printk("ip = %u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]); return; } do { dprintk("mpoa: (%s) ingress_purge_rcvd: removing an ingress entry, ip = %u.%u.%u.%u\n" , mpc->dev->name, ip[0], ip[1], ip[2], ip[3]); write_lock_bh(&mpc->ingress_lock); mpc->in_ops->remove_entry(entry, mpc); write_unlock_bh(&mpc->ingress_lock); mpc->in_ops->put(entry); entry = mpc->in_ops->get_with_mask(dst_ip, mpc, mask); } while (entry != NULL); return;} static void egress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc){ uint32_t cache_id = msg->content.eg_info.cache_id; eg_cache_entry *entry = mpc->eg_ops->get_by_cache_id(cache_id, mpc); if (entry == NULL) { dprintk("mpoa: (%s) egress_purge_rcvd: purge for a non-existing entry\n", mpc->dev->name); return; } write_lock_irq(&mpc->egress_lock); mpc->eg_ops->remove_entry(entry, mpc); write_unlock_irq(&mpc->egress_lock); mpc->eg_ops->put(entry); return;} static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry){ struct k_message *purge_msg; struct sk_buff *skb; dprintk("mpoa: purge_egress_shortcut: entering\n"); if (vcc == NULL) { printk("mpoa: purge_egress_shortcut: vcc == NULL\n"); return; } skb = alloc_skb(sizeof(struct k_message), GFP_ATOMIC); if (skb == NULL) { printk("mpoa: purge_egress_shortcut: out of memory\n"); return; } skb_put(skb, sizeof(struct k_message)); memset(skb->data, 0, sizeof(struct k_message)); purge_msg = (struct k_message *)skb->data; purge_msg->type = DATA_PLANE_PURGE; if (entry != NULL) purge_msg->content.eg_info = entry->ctrl_info; atm_force_charge(vcc, skb->truesize); skb_queue_tail(&vcc->recvq, skb); wake_up(&vcc->sleep); dprintk("mpoa: purge_egress_shortcut: exiting:\n"); return;}/* * Our MPS died. Tell our daemon to send NHRP data plane purge to each * of the egress shortcuts we have. */static void mps_death( struct k_message * msg, struct mpoa_client * mpc ){ eg_cache_entry *entry; dprintk("mpoa: (%s) mps_death:\n", mpc->dev->name); if(memcmp(msg->MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN)){ printk("mpoa: (%s) mps_death: wrong MPS\n", mpc->dev->name); return; } /* FIXME: This knows too much of the cache structure */ read_lock_irq(&mpc->egress_lock); entry = mpc->eg_cache; while (entry != NULL) { purge_egress_shortcut(entry->shortcut, entry); entry = entry->next; } read_unlock_irq(&mpc->egress_lock); mpc->in_ops->destroy_cache(mpc); mpc->eg_ops->destroy_cache(mpc); return;}static void MPOA_cache_impos_rcvd( struct k_message * msg, struct mpoa_client * mpc){ uint16_t holding_time; eg_cache_entry *entry = mpc->eg_ops->get_by_cache_id(msg->content.eg_info.cache_id, mpc); holding_time = msg->content.eg_info.holding_time; dprintk("mpoa: (%s) MPOA_cache_impos_rcvd: entry = %p, holding_time = %u\n", mpc->dev->name, entry, holding_time); if(entry == NULL && holding_time) { entry = mpc->eg_ops->add_entry(msg, mpc); mpc->eg_ops->put(entry); return; } if(holding_time){ mpc->eg_ops->update(entry, holding_time); return; } write_lock_irq(&mpc->egress_lock); mpc->eg_ops->remove_entry(entry, mpc); write_unlock_irq(&mpc->egress_lock); mpc->eg_ops->put(entry); return;}static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg, struct mpoa_client *mpc){ struct lec_priv *priv; int i, retval ; uint8_t tlv[4 + 1 + 1 + 1 + ATM_ESA_LEN]; tlv[0] = 00; tlv[1] = 0xa0; tlv[2] = 0x3e; tlv[3] = 0x2a; /* type */ tlv[4] = 1 + 1 + ATM_ESA_LEN; /* length */ tlv[5] = 0x02; /* MPOA client */ tlv[6] = 0x00; /* number of MPS MAC addresses */ memcpy(&tlv[7], mesg->MPS_ctrl, ATM_ESA_LEN); /* MPC ctrl ATM addr */ memcpy(mpc->our_ctrl_addr, mesg->MPS_ctrl, ATM_ESA_LEN); dprintk("mpoa: (%s) setting MPC ctrl ATM address to ", (mpc->dev) ? mpc->dev->name : "<unknown>"); for (i = 7; i < sizeof(tlv); i++) dprintk("%02x ", tlv[i]); dprintk("\n"); if (mpc->dev) { priv = (struct lec_priv *)mpc->dev->priv; retval = priv->lane2_ops->associate_req(mpc->dev, mpc->dev->dev_addr, tlv, sizeof(tlv)); if (retval == 0) printk("mpoa: (%s) MPOA device type TLV association failed\n", mpc->dev->name); retval = priv->lane2_ops->resolve(mpc->dev, NULL, 1, NULL, NULL); if (retval < 0) printk("mpoa: (%s) targetless LE_ARP request failed\n", mpc->dev->name); } return;}static void set_mps_mac_addr_rcvd(struct k_message *msg, struct mpoa_client *client){ if(client->number_of_mps_macs) kfree(client->mps_macs); client->number_of_mps_macs = 0; client->mps_macs = kmalloc(ETH_ALEN,GFP_KERNEL); if (client->mps_macs == NULL) { printk("mpoa: set_mps_mac_addr_rcvd: out of memory\n"); return; } client->number_of_mps_macs = 1; memcpy(client->mps_macs, msg->MPS_ctrl, ETH_ALEN); return;}/* * 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("mpoa: 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); return;}static void mpc_timer_refresh(){ mpc_timer.expires = jiffies + (MPC_P2 * HZ); mpc_timer.data = mpc_timer.expires; mpc_timer.function = mpc_cache_check; add_timer(&mpc_timer); return;}static void mpc_cache_check( unsigned long checking_time ){ struct mpoa_client *mpc = mpcs; static unsigned long previous_resolving_check_time = 0; static unsigned long previous_refresh_time = 0; while( mpc != NULL ){ mpc->in_ops->clear_count(mpc); mpc->eg_ops->clear_expired(mpc); if(checking_time - previous_resolving_check_time > mpc->parameters.mpc_p4 * HZ ){ mpc->in_ops->check_resolving(mpc); previous_resolving_check_time = checking_time; } if(checking_time - previous_refresh_time > mpc->parameters.mpc_p5 * HZ ){ mpc->in_ops->refresh(mpc); previous_refresh_time = checking_time; } mpc = mpc->next; } mpc_timer_refresh(); return;}void atm_mpoa_init_ops(struct atm_mpoa_ops *ops){ ops->mpoad_attach = atm_mpoa_mpoad_attach; ops->vcc_attach = atm_mpoa_vcc_attach;#ifdef CONFIG_PROC_FS if(mpc_proc_init() != 0) printk(KERN_INFO "mpoa: failed to initialize /proc/mpoa\n"); else printk(KERN_INFO "mpoa: /proc/mpoa initialized\n");#endif printk("mpc.c: " __DATE__ " " __TIME__ " initialized\n"); return;}#ifdef MODULEint init_module(void){ extern struct atm_mpoa_ops atm_mpoa_ops; atm_mpoa_init_ops(&atm_mpoa_ops); return 0;}void cleanup_module(void){ extern struct atm_mpoa_ops atm_mpoa_ops; struct mpoa_client *mpc, *tmp; struct atm_mpoa_qos *qos, *nextqos; struct lec_priv *priv; if (MOD_IN_USE) { printk("mpc.c: module in use\n"); return; }#ifdef CONFIG_PROC_FS mpc_proc_clean();#endif del_timer(&mpc_timer); unregister_netdevice_notifier(&mpoa_notifier); atm_mpoa_ops.mpoad_attach = NULL; atm_mpoa_ops.vcc_attach = NULL; mpc = mpcs; mpcs = NULL; while (mpc != NULL) { tmp = mpc->next; if (mpc->dev != NULL) { stop_mpc(mpc); priv = (struct lec_priv *)mpc->dev->priv; if (priv->lane2_ops != NULL) priv->lane2_ops->associate_indicator = NULL; } ddprintk("mpoa: cleanup_module: about to clear caches\n"); mpc->in_ops->destroy_cache(mpc); mpc->eg_ops->destroy_cache(mpc); ddprintk("mpoa: cleanup_module: caches cleared\n"); kfree(mpc->mps_macs); memset(mpc, 0, sizeof(struct mpoa_client)); ddprintk("mpoa: cleanup_module: about to kfree %p\n", mpc); kfree(mpc); ddprintk("mpoa: cleanup_module: next mpc is at %p\n", tmp); mpc = tmp; } qos = qos_head; qos_head = NULL; while (qos != NULL) { nextqos = qos->next; dprintk("mpoa: cleanup_module: freeing qos entry %p\n", qos); kfree(qos); qos = nextqos; } return;}#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -