11da177e4SLinus Torvalds #include <linux/types.h> 21da177e4SLinus Torvalds #include <linux/atmmpc.h> 35a0e3ad6STejun Heo #include <linux/slab.h> 41da177e4SLinus Torvalds #include <linux/time.h> 51da177e4SLinus Torvalds 61da177e4SLinus Torvalds #include "mpoa_caches.h" 71da177e4SLinus Torvalds #include "mpc.h" 81da177e4SLinus Torvalds 91da177e4SLinus Torvalds /* 101da177e4SLinus Torvalds * mpoa_caches.c: Implementation of ingress and egress cache 111da177e4SLinus Torvalds * handling functions 121da177e4SLinus Torvalds */ 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds #if 0 15b50c2ea7SJoe Perches #define dprintk(format, args...) \ 16b50c2ea7SJoe Perches printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */ 171da177e4SLinus Torvalds #else 18bee67d34SJoe Perches #define dprintk(format, args...) \ 19b50c2ea7SJoe Perches do { if (0) \ 20b50c2ea7SJoe Perches printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\ 21b50c2ea7SJoe Perches } while (0) 221da177e4SLinus Torvalds #endif 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds #if 0 25b50c2ea7SJoe Perches #define ddprintk(format, args...) \ 26b50c2ea7SJoe Perches printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */ 271da177e4SLinus Torvalds #else 28bee67d34SJoe Perches #define ddprintk(format, args...) \ 29b50c2ea7SJoe Perches do { if (0) \ 30b50c2ea7SJoe Perches printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\ 31b50c2ea7SJoe Perches } while (0) 321da177e4SLinus Torvalds #endif 331da177e4SLinus Torvalds 3430d492daSAl Viro static in_cache_entry *in_cache_get(__be32 dst_ip, 351da177e4SLinus Torvalds struct mpoa_client *client) 361da177e4SLinus Torvalds { 371da177e4SLinus Torvalds in_cache_entry *entry; 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds read_lock_bh(&client->ingress_lock); 401da177e4SLinus Torvalds entry = client->in_cache; 411da177e4SLinus Torvalds while (entry != NULL) { 421da177e4SLinus Torvalds if (entry->ctrl_info.in_dst_ip == dst_ip) { 4393714912SReshetova, Elena refcount_inc(&entry->use); 441da177e4SLinus Torvalds read_unlock_bh(&client->ingress_lock); 451da177e4SLinus Torvalds return entry; 461da177e4SLinus Torvalds } 471da177e4SLinus Torvalds entry = entry->next; 481da177e4SLinus Torvalds } 491da177e4SLinus Torvalds read_unlock_bh(&client->ingress_lock); 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds return NULL; 521da177e4SLinus Torvalds } 531da177e4SLinus Torvalds 5430d492daSAl Viro static in_cache_entry *in_cache_get_with_mask(__be32 dst_ip, 551da177e4SLinus Torvalds struct mpoa_client *client, 5630d492daSAl Viro __be32 mask) 571da177e4SLinus Torvalds { 581da177e4SLinus Torvalds in_cache_entry *entry; 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds read_lock_bh(&client->ingress_lock); 611da177e4SLinus Torvalds entry = client->in_cache; 621da177e4SLinus Torvalds while (entry != NULL) { 631da177e4SLinus Torvalds if ((entry->ctrl_info.in_dst_ip & mask) == (dst_ip & mask)) { 6493714912SReshetova, Elena refcount_inc(&entry->use); 651da177e4SLinus Torvalds read_unlock_bh(&client->ingress_lock); 661da177e4SLinus Torvalds return entry; 671da177e4SLinus Torvalds } 681da177e4SLinus Torvalds entry = entry->next; 691da177e4SLinus Torvalds } 701da177e4SLinus Torvalds read_unlock_bh(&client->ingress_lock); 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds return NULL; 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds } 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds static in_cache_entry *in_cache_get_by_vcc(struct atm_vcc *vcc, 771da177e4SLinus Torvalds struct mpoa_client *client) 781da177e4SLinus Torvalds { 791da177e4SLinus Torvalds in_cache_entry *entry; 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds read_lock_bh(&client->ingress_lock); 821da177e4SLinus Torvalds entry = client->in_cache; 831da177e4SLinus Torvalds while (entry != NULL) { 841da177e4SLinus Torvalds if (entry->shortcut == vcc) { 8593714912SReshetova, Elena refcount_inc(&entry->use); 861da177e4SLinus Torvalds read_unlock_bh(&client->ingress_lock); 871da177e4SLinus Torvalds return entry; 881da177e4SLinus Torvalds } 891da177e4SLinus Torvalds entry = entry->next; 901da177e4SLinus Torvalds } 911da177e4SLinus Torvalds read_unlock_bh(&client->ingress_lock); 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds return NULL; 941da177e4SLinus Torvalds } 951da177e4SLinus Torvalds 9630d492daSAl Viro static in_cache_entry *in_cache_add_entry(__be32 dst_ip, 971da177e4SLinus Torvalds struct mpoa_client *client) 981da177e4SLinus Torvalds { 992afe37cdSArnaldo Carvalho de Melo in_cache_entry *entry = kzalloc(sizeof(in_cache_entry), GFP_KERNEL); 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds if (entry == NULL) { 102bee67d34SJoe Perches pr_info("mpoa: mpoa_caches.c: new_in_cache_entry: out of memory\n"); 1031da177e4SLinus Torvalds return NULL; 1041da177e4SLinus Torvalds } 1051da177e4SLinus Torvalds 106b50c2ea7SJoe Perches dprintk("adding an ingress entry, ip = %pI4\n", &dst_ip); 1071da177e4SLinus Torvalds 10893714912SReshetova, Elena refcount_set(&entry->use, 1); 109b50c2ea7SJoe Perches dprintk("new_in_cache_entry: about to lock\n"); 1101da177e4SLinus Torvalds write_lock_bh(&client->ingress_lock); 1111da177e4SLinus Torvalds entry->next = client->in_cache; 1121da177e4SLinus Torvalds entry->prev = NULL; 1131da177e4SLinus Torvalds if (client->in_cache != NULL) 1141da177e4SLinus Torvalds client->in_cache->prev = entry; 1151da177e4SLinus Torvalds client->in_cache = entry; 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds memcpy(entry->MPS_ctrl_ATM_addr, client->mps_ctrl_addr, ATM_ESA_LEN); 1181da177e4SLinus Torvalds entry->ctrl_info.in_dst_ip = dst_ip; 1191da177e4SLinus Torvalds do_gettimeofday(&(entry->tv)); 1201da177e4SLinus Torvalds entry->retry_time = client->parameters.mpc_p4; 1211da177e4SLinus Torvalds entry->count = 1; 1221da177e4SLinus Torvalds entry->entry_state = INGRESS_INVALID; 1231da177e4SLinus Torvalds entry->ctrl_info.holding_time = HOLDING_TIME_DEFAULT; 12493714912SReshetova, Elena refcount_inc(&entry->use); 1251da177e4SLinus Torvalds 1261da177e4SLinus Torvalds write_unlock_bh(&client->ingress_lock); 127b50c2ea7SJoe Perches dprintk("new_in_cache_entry: unlocked\n"); 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds return entry; 1301da177e4SLinus Torvalds } 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds static int cache_hit(in_cache_entry *entry, struct mpoa_client *mpc) 1331da177e4SLinus Torvalds { 1341da177e4SLinus Torvalds struct atm_mpoa_qos *qos; 1351da177e4SLinus Torvalds struct k_message msg; 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds entry->count++; 1381da177e4SLinus Torvalds if (entry->entry_state == INGRESS_RESOLVED && entry->shortcut != NULL) 1391da177e4SLinus Torvalds return OPEN; 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds if (entry->entry_state == INGRESS_REFRESHING) { 1421da177e4SLinus Torvalds if (entry->count > mpc->parameters.mpc_p1) { 1431da177e4SLinus Torvalds msg.type = SND_MPOA_RES_RQST; 1441da177e4SLinus Torvalds msg.content.in_info = entry->ctrl_info; 1451da177e4SLinus Torvalds memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN); 1461da177e4SLinus Torvalds qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); 147bee67d34SJoe Perches if (qos != NULL) 148bee67d34SJoe Perches msg.qos = qos->qos; 1491da177e4SLinus Torvalds msg_to_mpoad(&msg, mpc); 1501da177e4SLinus Torvalds do_gettimeofday(&(entry->reply_wait)); 1511da177e4SLinus Torvalds entry->entry_state = INGRESS_RESOLVING; 1521da177e4SLinus Torvalds } 1531da177e4SLinus Torvalds if (entry->shortcut != NULL) 1541da177e4SLinus Torvalds return OPEN; 1551da177e4SLinus Torvalds return CLOSED; 1561da177e4SLinus Torvalds } 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds if (entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL) 1591da177e4SLinus Torvalds return OPEN; 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds if (entry->count > mpc->parameters.mpc_p1 && 1621da177e4SLinus Torvalds entry->entry_state == INGRESS_INVALID) { 163b50c2ea7SJoe Perches dprintk("(%s) threshold exceeded for ip %pI4, sending MPOA res req\n", 16421454aaaSHarvey Harrison mpc->dev->name, &entry->ctrl_info.in_dst_ip); 1651da177e4SLinus Torvalds entry->entry_state = INGRESS_RESOLVING; 1661da177e4SLinus Torvalds msg.type = SND_MPOA_RES_RQST; 1671da177e4SLinus Torvalds memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN); 1681da177e4SLinus Torvalds msg.content.in_info = entry->ctrl_info; 1691da177e4SLinus Torvalds qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); 170bee67d34SJoe Perches if (qos != NULL) 171bee67d34SJoe Perches msg.qos = qos->qos; 1721da177e4SLinus Torvalds msg_to_mpoad(&msg, mpc); 1731da177e4SLinus Torvalds do_gettimeofday(&(entry->reply_wait)); 1741da177e4SLinus Torvalds } 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds return CLOSED; 1771da177e4SLinus Torvalds } 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds static void in_cache_put(in_cache_entry *entry) 1801da177e4SLinus Torvalds { 18193714912SReshetova, Elena if (refcount_dec_and_test(&entry->use)) { 1821da177e4SLinus Torvalds memset(entry, 0, sizeof(in_cache_entry)); 1831da177e4SLinus Torvalds kfree(entry); 1841da177e4SLinus Torvalds } 1851da177e4SLinus Torvalds } 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds /* 1881da177e4SLinus Torvalds * This should be called with write lock on 1891da177e4SLinus Torvalds */ 1901da177e4SLinus Torvalds static void in_cache_remove_entry(in_cache_entry *entry, 1911da177e4SLinus Torvalds struct mpoa_client *client) 1921da177e4SLinus Torvalds { 1931da177e4SLinus Torvalds struct atm_vcc *vcc; 1941da177e4SLinus Torvalds struct k_message msg; 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds vcc = entry->shortcut; 197b50c2ea7SJoe Perches dprintk("removing an ingress entry, ip = %pI4\n", 19821454aaaSHarvey Harrison &entry->ctrl_info.in_dst_ip); 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds if (entry->prev != NULL) 2011da177e4SLinus Torvalds entry->prev->next = entry->next; 2021da177e4SLinus Torvalds else 2031da177e4SLinus Torvalds client->in_cache = entry->next; 2041da177e4SLinus Torvalds if (entry->next != NULL) 2051da177e4SLinus Torvalds entry->next->prev = entry->prev; 2061da177e4SLinus Torvalds client->in_ops->put(entry); 2071da177e4SLinus Torvalds if (client->in_cache == NULL && client->eg_cache == NULL) { 2081da177e4SLinus Torvalds msg.type = STOP_KEEP_ALIVE_SM; 2091da177e4SLinus Torvalds msg_to_mpoad(&msg, client); 2101da177e4SLinus Torvalds } 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds /* Check if the egress side still uses this VCC */ 2131da177e4SLinus Torvalds if (vcc != NULL) { 214bee67d34SJoe Perches eg_cache_entry *eg_entry = client->eg_ops->get_by_vcc(vcc, 215bee67d34SJoe Perches client); 2161da177e4SLinus Torvalds if (eg_entry != NULL) { 2171da177e4SLinus Torvalds client->eg_ops->put(eg_entry); 2181da177e4SLinus Torvalds return; 2191da177e4SLinus Torvalds } 2201da177e4SLinus Torvalds vcc_release_async(vcc, -EPIPE); 2211da177e4SLinus Torvalds } 2221da177e4SLinus Torvalds } 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds /* Call this every MPC-p2 seconds... Not exactly correct solution, 2251da177e4SLinus Torvalds but an easy one... */ 2261da177e4SLinus Torvalds static void clear_count_and_expired(struct mpoa_client *client) 2271da177e4SLinus Torvalds { 2281da177e4SLinus Torvalds in_cache_entry *entry, *next_entry; 2291da177e4SLinus Torvalds struct timeval now; 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds do_gettimeofday(&now); 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds write_lock_bh(&client->ingress_lock); 2341da177e4SLinus Torvalds entry = client->in_cache; 2351da177e4SLinus Torvalds while (entry != NULL) { 2361da177e4SLinus Torvalds entry->count = 0; 2371da177e4SLinus Torvalds next_entry = entry->next; 2381da177e4SLinus Torvalds if ((now.tv_sec - entry->tv.tv_sec) 2391da177e4SLinus Torvalds > entry->ctrl_info.holding_time) { 240b50c2ea7SJoe Perches dprintk("holding time expired, ip = %pI4\n", 24121454aaaSHarvey Harrison &entry->ctrl_info.in_dst_ip); 2421da177e4SLinus Torvalds client->in_ops->remove_entry(entry, client); 2431da177e4SLinus Torvalds } 2441da177e4SLinus Torvalds entry = next_entry; 2451da177e4SLinus Torvalds } 2461da177e4SLinus Torvalds write_unlock_bh(&client->ingress_lock); 2471da177e4SLinus Torvalds } 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds /* Call this every MPC-p4 seconds. */ 2501da177e4SLinus Torvalds static void check_resolving_entries(struct mpoa_client *client) 2511da177e4SLinus Torvalds { 2521da177e4SLinus Torvalds 2531da177e4SLinus Torvalds struct atm_mpoa_qos *qos; 2541da177e4SLinus Torvalds in_cache_entry *entry; 2551da177e4SLinus Torvalds struct timeval now; 2561da177e4SLinus Torvalds struct k_message msg; 2571da177e4SLinus Torvalds 2581da177e4SLinus Torvalds do_gettimeofday(&now); 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds read_lock_bh(&client->ingress_lock); 2611da177e4SLinus Torvalds entry = client->in_cache; 2621da177e4SLinus Torvalds while (entry != NULL) { 2631da177e4SLinus Torvalds if (entry->entry_state == INGRESS_RESOLVING) { 264bee67d34SJoe Perches if ((now.tv_sec - entry->hold_down.tv_sec) < 265bee67d34SJoe Perches client->parameters.mpc_p6) { 2661da177e4SLinus Torvalds entry = entry->next; /* Entry in hold down */ 2671da177e4SLinus Torvalds continue; 2681da177e4SLinus Torvalds } 2691da177e4SLinus Torvalds if ((now.tv_sec - entry->reply_wait.tv_sec) > 2701da177e4SLinus Torvalds entry->retry_time) { 2711da177e4SLinus Torvalds entry->retry_time = MPC_C1 * (entry->retry_time); 272bee67d34SJoe Perches /* 273bee67d34SJoe Perches * Retry time maximum exceeded, 274bee67d34SJoe Perches * put entry in hold down. 275bee67d34SJoe Perches */ 2761da177e4SLinus Torvalds if (entry->retry_time > client->parameters.mpc_p5) { 2771da177e4SLinus Torvalds do_gettimeofday(&(entry->hold_down)); 2781da177e4SLinus Torvalds entry->retry_time = client->parameters.mpc_p4; 2791da177e4SLinus Torvalds entry = entry->next; 2801da177e4SLinus Torvalds continue; 2811da177e4SLinus Torvalds } 2821da177e4SLinus Torvalds /* Ask daemon to send a resolution request. */ 2831da177e4SLinus Torvalds memset(&(entry->hold_down), 0, sizeof(struct timeval)); 2841da177e4SLinus Torvalds msg.type = SND_MPOA_RES_RTRY; 2851da177e4SLinus Torvalds memcpy(msg.MPS_ctrl, client->mps_ctrl_addr, ATM_ESA_LEN); 2861da177e4SLinus Torvalds msg.content.in_info = entry->ctrl_info; 2871da177e4SLinus Torvalds qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); 288bee67d34SJoe Perches if (qos != NULL) 289bee67d34SJoe Perches msg.qos = qos->qos; 2901da177e4SLinus Torvalds msg_to_mpoad(&msg, client); 2911da177e4SLinus Torvalds do_gettimeofday(&(entry->reply_wait)); 2921da177e4SLinus Torvalds } 2931da177e4SLinus Torvalds } 2941da177e4SLinus Torvalds entry = entry->next; 2951da177e4SLinus Torvalds } 2961da177e4SLinus Torvalds read_unlock_bh(&client->ingress_lock); 2971da177e4SLinus Torvalds } 2981da177e4SLinus Torvalds 2991da177e4SLinus Torvalds /* Call this every MPC-p5 seconds. */ 3001da177e4SLinus Torvalds static void refresh_entries(struct mpoa_client *client) 3011da177e4SLinus Torvalds { 3021da177e4SLinus Torvalds struct timeval now; 3031da177e4SLinus Torvalds struct in_cache_entry *entry = client->in_cache; 3041da177e4SLinus Torvalds 305b50c2ea7SJoe Perches ddprintk("refresh_entries\n"); 3061da177e4SLinus Torvalds do_gettimeofday(&now); 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds read_lock_bh(&client->ingress_lock); 3091da177e4SLinus Torvalds while (entry != NULL) { 3101da177e4SLinus Torvalds if (entry->entry_state == INGRESS_RESOLVED) { 3111da177e4SLinus Torvalds if (!(entry->refresh_time)) 3121da177e4SLinus Torvalds entry->refresh_time = (2 * (entry->ctrl_info.holding_time))/3; 313bee67d34SJoe Perches if ((now.tv_sec - entry->reply_wait.tv_sec) > 314bee67d34SJoe Perches entry->refresh_time) { 315b50c2ea7SJoe Perches dprintk("refreshing an entry.\n"); 3161da177e4SLinus Torvalds entry->entry_state = INGRESS_REFRESHING; 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds } 3191da177e4SLinus Torvalds } 3201da177e4SLinus Torvalds entry = entry->next; 3211da177e4SLinus Torvalds } 3221da177e4SLinus Torvalds read_unlock_bh(&client->ingress_lock); 3231da177e4SLinus Torvalds } 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds static void in_destroy_cache(struct mpoa_client *mpc) 3261da177e4SLinus Torvalds { 3271da177e4SLinus Torvalds write_lock_irq(&mpc->ingress_lock); 3281da177e4SLinus Torvalds while (mpc->in_cache != NULL) 3291da177e4SLinus Torvalds mpc->in_ops->remove_entry(mpc->in_cache, mpc); 3301da177e4SLinus Torvalds write_unlock_irq(&mpc->ingress_lock); 3311da177e4SLinus Torvalds } 3321da177e4SLinus Torvalds 333bee67d34SJoe Perches static eg_cache_entry *eg_cache_get_by_cache_id(__be32 cache_id, 334bee67d34SJoe Perches struct mpoa_client *mpc) 3351da177e4SLinus Torvalds { 3361da177e4SLinus Torvalds eg_cache_entry *entry; 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds read_lock_irq(&mpc->egress_lock); 3391da177e4SLinus Torvalds entry = mpc->eg_cache; 3401da177e4SLinus Torvalds while (entry != NULL) { 3411da177e4SLinus Torvalds if (entry->ctrl_info.cache_id == cache_id) { 342e00bdbefSReshetova, Elena refcount_inc(&entry->use); 3431da177e4SLinus Torvalds read_unlock_irq(&mpc->egress_lock); 3441da177e4SLinus Torvalds return entry; 3451da177e4SLinus Torvalds } 3461da177e4SLinus Torvalds entry = entry->next; 3471da177e4SLinus Torvalds } 3481da177e4SLinus Torvalds read_unlock_irq(&mpc->egress_lock); 3491da177e4SLinus Torvalds 3501da177e4SLinus Torvalds return NULL; 3511da177e4SLinus Torvalds } 3521da177e4SLinus Torvalds 3531da177e4SLinus Torvalds /* This can be called from any context since it saves CPU flags */ 35430d492daSAl Viro static eg_cache_entry *eg_cache_get_by_tag(__be32 tag, struct mpoa_client *mpc) 3551da177e4SLinus Torvalds { 3561da177e4SLinus Torvalds unsigned long flags; 3571da177e4SLinus Torvalds eg_cache_entry *entry; 3581da177e4SLinus Torvalds 3591da177e4SLinus Torvalds read_lock_irqsave(&mpc->egress_lock, flags); 3601da177e4SLinus Torvalds entry = mpc->eg_cache; 3611da177e4SLinus Torvalds while (entry != NULL) { 3621da177e4SLinus Torvalds if (entry->ctrl_info.tag == tag) { 363e00bdbefSReshetova, Elena refcount_inc(&entry->use); 3641da177e4SLinus Torvalds read_unlock_irqrestore(&mpc->egress_lock, flags); 3651da177e4SLinus Torvalds return entry; 3661da177e4SLinus Torvalds } 3671da177e4SLinus Torvalds entry = entry->next; 3681da177e4SLinus Torvalds } 3691da177e4SLinus Torvalds read_unlock_irqrestore(&mpc->egress_lock, flags); 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds return NULL; 3721da177e4SLinus Torvalds } 3731da177e4SLinus Torvalds 3741da177e4SLinus Torvalds /* This can be called from any context since it saves CPU flags */ 375bee67d34SJoe Perches static eg_cache_entry *eg_cache_get_by_vcc(struct atm_vcc *vcc, 376bee67d34SJoe Perches struct mpoa_client *mpc) 3771da177e4SLinus Torvalds { 3781da177e4SLinus Torvalds unsigned long flags; 3791da177e4SLinus Torvalds eg_cache_entry *entry; 3801da177e4SLinus Torvalds 3811da177e4SLinus Torvalds read_lock_irqsave(&mpc->egress_lock, flags); 3821da177e4SLinus Torvalds entry = mpc->eg_cache; 3831da177e4SLinus Torvalds while (entry != NULL) { 3841da177e4SLinus Torvalds if (entry->shortcut == vcc) { 385e00bdbefSReshetova, Elena refcount_inc(&entry->use); 3861da177e4SLinus Torvalds read_unlock_irqrestore(&mpc->egress_lock, flags); 3871da177e4SLinus Torvalds return entry; 3881da177e4SLinus Torvalds } 3891da177e4SLinus Torvalds entry = entry->next; 3901da177e4SLinus Torvalds } 3911da177e4SLinus Torvalds read_unlock_irqrestore(&mpc->egress_lock, flags); 3921da177e4SLinus Torvalds 3931da177e4SLinus Torvalds return NULL; 3941da177e4SLinus Torvalds } 3951da177e4SLinus Torvalds 396bee67d34SJoe Perches static eg_cache_entry *eg_cache_get_by_src_ip(__be32 ipaddr, 397bee67d34SJoe Perches struct mpoa_client *mpc) 3981da177e4SLinus Torvalds { 3991da177e4SLinus Torvalds eg_cache_entry *entry; 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds read_lock_irq(&mpc->egress_lock); 4021da177e4SLinus Torvalds entry = mpc->eg_cache; 4031da177e4SLinus Torvalds while (entry != NULL) { 4041da177e4SLinus Torvalds if (entry->latest_ip_addr == ipaddr) { 405e00bdbefSReshetova, Elena refcount_inc(&entry->use); 4061da177e4SLinus Torvalds read_unlock_irq(&mpc->egress_lock); 4071da177e4SLinus Torvalds return entry; 4081da177e4SLinus Torvalds } 4091da177e4SLinus Torvalds entry = entry->next; 4101da177e4SLinus Torvalds } 4111da177e4SLinus Torvalds read_unlock_irq(&mpc->egress_lock); 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds return NULL; 4141da177e4SLinus Torvalds } 4151da177e4SLinus Torvalds 4161da177e4SLinus Torvalds static void eg_cache_put(eg_cache_entry *entry) 4171da177e4SLinus Torvalds { 418e00bdbefSReshetova, Elena if (refcount_dec_and_test(&entry->use)) { 4191da177e4SLinus Torvalds memset(entry, 0, sizeof(eg_cache_entry)); 4201da177e4SLinus Torvalds kfree(entry); 4211da177e4SLinus Torvalds } 4221da177e4SLinus Torvalds } 4231da177e4SLinus Torvalds 4241da177e4SLinus Torvalds /* 4251da177e4SLinus Torvalds * This should be called with write lock on 4261da177e4SLinus Torvalds */ 4271da177e4SLinus Torvalds static void eg_cache_remove_entry(eg_cache_entry *entry, 4281da177e4SLinus Torvalds struct mpoa_client *client) 4291da177e4SLinus Torvalds { 4301da177e4SLinus Torvalds struct atm_vcc *vcc; 4311da177e4SLinus Torvalds struct k_message msg; 4321da177e4SLinus Torvalds 4331da177e4SLinus Torvalds vcc = entry->shortcut; 434b50c2ea7SJoe Perches dprintk("removing an egress entry.\n"); 4351da177e4SLinus Torvalds if (entry->prev != NULL) 4361da177e4SLinus Torvalds entry->prev->next = entry->next; 4371da177e4SLinus Torvalds else 4381da177e4SLinus Torvalds client->eg_cache = entry->next; 4391da177e4SLinus Torvalds if (entry->next != NULL) 4401da177e4SLinus Torvalds entry->next->prev = entry->prev; 4411da177e4SLinus Torvalds client->eg_ops->put(entry); 4421da177e4SLinus Torvalds if (client->in_cache == NULL && client->eg_cache == NULL) { 4431da177e4SLinus Torvalds msg.type = STOP_KEEP_ALIVE_SM; 4441da177e4SLinus Torvalds msg_to_mpoad(&msg, client); 4451da177e4SLinus Torvalds } 4461da177e4SLinus Torvalds 4471da177e4SLinus Torvalds /* Check if the ingress side still uses this VCC */ 4481da177e4SLinus Torvalds if (vcc != NULL) { 4491da177e4SLinus Torvalds in_cache_entry *in_entry = client->in_ops->get_by_vcc(vcc, client); 4501da177e4SLinus Torvalds if (in_entry != NULL) { 4511da177e4SLinus Torvalds client->in_ops->put(in_entry); 4521da177e4SLinus Torvalds return; 4531da177e4SLinus Torvalds } 4541da177e4SLinus Torvalds vcc_release_async(vcc, -EPIPE); 4551da177e4SLinus Torvalds } 4561da177e4SLinus Torvalds } 4571da177e4SLinus Torvalds 458bee67d34SJoe Perches static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, 459bee67d34SJoe Perches struct mpoa_client *client) 4601da177e4SLinus Torvalds { 4612afe37cdSArnaldo Carvalho de Melo eg_cache_entry *entry = kzalloc(sizeof(eg_cache_entry), GFP_KERNEL); 4621da177e4SLinus Torvalds 4631da177e4SLinus Torvalds if (entry == NULL) { 464bee67d34SJoe Perches pr_info("out of memory\n"); 4651da177e4SLinus Torvalds return NULL; 4661da177e4SLinus Torvalds } 4671da177e4SLinus Torvalds 468b50c2ea7SJoe Perches dprintk("adding an egress entry, ip = %pI4, this should be our IP\n", 46921454aaaSHarvey Harrison &msg->content.eg_info.eg_dst_ip); 4701da177e4SLinus Torvalds 471e00bdbefSReshetova, Elena refcount_set(&entry->use, 1); 472b50c2ea7SJoe Perches dprintk("new_eg_cache_entry: about to lock\n"); 4731da177e4SLinus Torvalds write_lock_irq(&client->egress_lock); 4741da177e4SLinus Torvalds entry->next = client->eg_cache; 4751da177e4SLinus Torvalds entry->prev = NULL; 4761da177e4SLinus Torvalds if (client->eg_cache != NULL) 4771da177e4SLinus Torvalds client->eg_cache->prev = entry; 4781da177e4SLinus Torvalds client->eg_cache = entry; 4791da177e4SLinus Torvalds 4801da177e4SLinus Torvalds memcpy(entry->MPS_ctrl_ATM_addr, client->mps_ctrl_addr, ATM_ESA_LEN); 4811da177e4SLinus Torvalds entry->ctrl_info = msg->content.eg_info; 4821da177e4SLinus Torvalds do_gettimeofday(&(entry->tv)); 4831da177e4SLinus Torvalds entry->entry_state = EGRESS_RESOLVED; 484b50c2ea7SJoe Perches dprintk("new_eg_cache_entry cache_id %u\n", 485bee67d34SJoe Perches ntohl(entry->ctrl_info.cache_id)); 486b50c2ea7SJoe Perches dprintk("mps_ip = %pI4\n", &entry->ctrl_info.mps_ip); 487e00bdbefSReshetova, Elena refcount_inc(&entry->use); 4881da177e4SLinus Torvalds 4891da177e4SLinus Torvalds write_unlock_irq(&client->egress_lock); 490b50c2ea7SJoe Perches dprintk("new_eg_cache_entry: unlocked\n"); 4911da177e4SLinus Torvalds 4921da177e4SLinus Torvalds return entry; 4931da177e4SLinus Torvalds } 4941da177e4SLinus Torvalds 4951da177e4SLinus Torvalds static void update_eg_cache_entry(eg_cache_entry *entry, uint16_t holding_time) 4961da177e4SLinus Torvalds { 4971da177e4SLinus Torvalds do_gettimeofday(&(entry->tv)); 4981da177e4SLinus Torvalds entry->entry_state = EGRESS_RESOLVED; 4991da177e4SLinus Torvalds entry->ctrl_info.holding_time = holding_time; 5001da177e4SLinus Torvalds } 5011da177e4SLinus Torvalds 5021da177e4SLinus Torvalds static void clear_expired(struct mpoa_client *client) 5031da177e4SLinus Torvalds { 5041da177e4SLinus Torvalds eg_cache_entry *entry, *next_entry; 5051da177e4SLinus Torvalds struct timeval now; 5061da177e4SLinus Torvalds struct k_message msg; 5071da177e4SLinus Torvalds 5081da177e4SLinus Torvalds do_gettimeofday(&now); 5091da177e4SLinus Torvalds 5101da177e4SLinus Torvalds write_lock_irq(&client->egress_lock); 5111da177e4SLinus Torvalds entry = client->eg_cache; 5121da177e4SLinus Torvalds while (entry != NULL) { 5131da177e4SLinus Torvalds next_entry = entry->next; 5141da177e4SLinus Torvalds if ((now.tv_sec - entry->tv.tv_sec) 5151da177e4SLinus Torvalds > entry->ctrl_info.holding_time) { 5161da177e4SLinus Torvalds msg.type = SND_EGRESS_PURGE; 5171da177e4SLinus Torvalds msg.content.eg_info = entry->ctrl_info; 518b50c2ea7SJoe Perches dprintk("egress_cache: holding time expired, cache_id = %u.\n", 519bee67d34SJoe Perches ntohl(entry->ctrl_info.cache_id)); 5201da177e4SLinus Torvalds msg_to_mpoad(&msg, client); 5211da177e4SLinus Torvalds client->eg_ops->remove_entry(entry, client); 5221da177e4SLinus Torvalds } 5231da177e4SLinus Torvalds entry = next_entry; 5241da177e4SLinus Torvalds } 5251da177e4SLinus Torvalds write_unlock_irq(&client->egress_lock); 5261da177e4SLinus Torvalds } 5271da177e4SLinus Torvalds 5281da177e4SLinus Torvalds static void eg_destroy_cache(struct mpoa_client *mpc) 5291da177e4SLinus Torvalds { 5301da177e4SLinus Torvalds write_lock_irq(&mpc->egress_lock); 5311da177e4SLinus Torvalds while (mpc->eg_cache != NULL) 5321da177e4SLinus Torvalds mpc->eg_ops->remove_entry(mpc->eg_cache, mpc); 5331da177e4SLinus Torvalds write_unlock_irq(&mpc->egress_lock); 5341da177e4SLinus Torvalds } 5351da177e4SLinus Torvalds 5361da177e4SLinus Torvalds 5374dd191bbSJulia Lawall static const struct in_cache_ops ingress_ops = { 53899a5e178SKees Cook .add_entry = in_cache_add_entry, 53999a5e178SKees Cook .get = in_cache_get, 54099a5e178SKees Cook .get_with_mask = in_cache_get_with_mask, 54199a5e178SKees Cook .get_by_vcc = in_cache_get_by_vcc, 54299a5e178SKees Cook .put = in_cache_put, 54399a5e178SKees Cook .remove_entry = in_cache_remove_entry, 54499a5e178SKees Cook .cache_hit = cache_hit, 54599a5e178SKees Cook .clear_count = clear_count_and_expired, 54699a5e178SKees Cook .check_resolving = check_resolving_entries, 54799a5e178SKees Cook .refresh = refresh_entries, 54899a5e178SKees Cook .destroy_cache = in_destroy_cache 5491da177e4SLinus Torvalds }; 5501da177e4SLinus Torvalds 5514dd191bbSJulia Lawall static const struct eg_cache_ops egress_ops = { 55299a5e178SKees Cook .add_entry = eg_cache_add_entry, 55399a5e178SKees Cook .get_by_cache_id = eg_cache_get_by_cache_id, 55499a5e178SKees Cook .get_by_tag = eg_cache_get_by_tag, 55599a5e178SKees Cook .get_by_vcc = eg_cache_get_by_vcc, 55699a5e178SKees Cook .get_by_src_ip = eg_cache_get_by_src_ip, 55799a5e178SKees Cook .put = eg_cache_put, 55899a5e178SKees Cook .remove_entry = eg_cache_remove_entry, 55999a5e178SKees Cook .update = update_eg_cache_entry, 56099a5e178SKees Cook .clear_expired = clear_expired, 56199a5e178SKees Cook .destroy_cache = eg_destroy_cache 5621da177e4SLinus Torvalds }; 5631da177e4SLinus Torvalds 5641da177e4SLinus Torvalds void atm_mpoa_init_cache(struct mpoa_client *mpc) 5651da177e4SLinus Torvalds { 5661da177e4SLinus Torvalds mpc->in_ops = &ingress_ops; 5671da177e4SLinus Torvalds mpc->eg_ops = &egress_ops; 5681da177e4SLinus Torvalds } 569