mpoa_caches.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:15k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. #include <linux/types.h>
  2. #include <linux/atmmpc.h>
  3. #include <linux/time.h>
  4. #include "mpoa_caches.h"
  5. #include "mpc.h"
  6. /*
  7.  * mpoa_caches.c: Implementation of ingress and egress cache
  8.  * handling functions
  9.  */
  10. #if 0
  11. #define dprintk printk    /* debug */
  12. #else
  13. #define dprintk(format,args...)
  14. #endif
  15. #if 0
  16. #define ddprintk printk  /* more debug */
  17. #else
  18. #define ddprintk(format,args...)
  19. #endif
  20. static in_cache_entry *in_cache_get(uint32_t dst_ip,
  21.     struct mpoa_client *client)
  22. {
  23. in_cache_entry *entry;
  24. read_lock_bh(&client->ingress_lock);
  25. entry = client->in_cache;
  26. while(entry != NULL){
  27. if( entry->ctrl_info.in_dst_ip == dst_ip ){
  28. atomic_inc(&entry->use);
  29. read_unlock_bh(&client->ingress_lock);
  30. return entry;
  31. }
  32. entry = entry->next;
  33. }
  34. read_unlock_bh(&client->ingress_lock);
  35. return NULL;
  36. }
  37. static in_cache_entry *in_cache_get_with_mask(uint32_t dst_ip,
  38.       struct mpoa_client *client,
  39.       uint32_t mask)
  40. {
  41. in_cache_entry *entry;
  42. read_lock_bh(&client->ingress_lock);
  43. entry = client->in_cache;
  44. while(entry != NULL){
  45. if((entry->ctrl_info.in_dst_ip & mask)  == (dst_ip & mask )){
  46. atomic_inc(&entry->use);
  47. read_unlock_bh(&client->ingress_lock);
  48. return entry;
  49. }
  50. entry = entry->next;
  51. }
  52. read_unlock_bh(&client->ingress_lock);
  53. return NULL;
  54. }
  55. static in_cache_entry *in_cache_get_by_vcc(struct atm_vcc *vcc,
  56.    struct mpoa_client *client )
  57. {
  58. in_cache_entry *entry;
  59. read_lock_bh(&client->ingress_lock);
  60. entry = client->in_cache;
  61. while(entry != NULL){
  62. if(entry->shortcut == vcc) {
  63. atomic_inc(&entry->use);
  64. read_unlock_bh(&client->ingress_lock);
  65. return entry;
  66. }
  67. entry = entry->next;
  68. }
  69. read_unlock_bh(&client->ingress_lock);
  70. return NULL;
  71. }
  72. static in_cache_entry *in_cache_add_entry(uint32_t dst_ip,
  73.   struct mpoa_client *client)
  74. {
  75. unsigned char *ip __attribute__ ((unused)) = (unsigned char *)&dst_ip;
  76. in_cache_entry* entry = kmalloc(sizeof(in_cache_entry), GFP_KERNEL);
  77. if (entry == NULL) {
  78. printk("mpoa: mpoa_caches.c: new_in_cache_entry: out of memoryn");
  79. return NULL;
  80. }
  81. dprintk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %u.%u.%u.%un", ip[0], ip[1], ip[2], ip[3]);
  82. memset(entry,0,sizeof(in_cache_entry));
  83. atomic_set(&entry->use, 1);
  84. dprintk("mpoa: mpoa_caches.c: new_in_cache_entry: about to lockn");
  85. write_lock_bh(&client->ingress_lock);
  86. entry->next = client->in_cache;
  87. entry->prev = NULL;
  88. if (client->in_cache != NULL)
  89. client->in_cache->prev = entry;
  90. client->in_cache = entry;
  91. memcpy(entry->MPS_ctrl_ATM_addr, client->mps_ctrl_addr, ATM_ESA_LEN);
  92. entry->ctrl_info.in_dst_ip = dst_ip;
  93. do_gettimeofday(&(entry->tv));
  94. entry->retry_time = client->parameters.mpc_p4;
  95. entry->count = 1;
  96. entry->entry_state = INGRESS_INVALID;
  97. entry->ctrl_info.holding_time = HOLDING_TIME_DEFAULT;
  98. atomic_inc(&entry->use);
  99. write_unlock_bh(&client->ingress_lock);
  100. dprintk("mpoa: mpoa_caches.c: new_in_cache_entry: unlockedn");
  101. return entry;
  102. }
  103. static int cache_hit(in_cache_entry *entry, struct mpoa_client *mpc)
  104. {
  105. struct atm_mpoa_qos *qos;
  106. struct k_message msg;
  107. entry->count++;
  108. if(entry->entry_state == INGRESS_RESOLVED && entry->shortcut != NULL)
  109. return OPEN;
  110. if(entry->entry_state == INGRESS_REFRESHING){
  111. if(entry->count > mpc->parameters.mpc_p1){
  112. msg.type = SND_MPOA_RES_RQST;
  113. msg.content.in_info = entry->ctrl_info;
  114. memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN);
  115. qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip);
  116. if (qos != NULL) msg.qos = qos->qos;
  117. msg_to_mpoad(&msg, mpc);
  118. do_gettimeofday(&(entry->reply_wait));
  119. entry->entry_state = INGRESS_RESOLVING;
  120. }
  121. if(entry->shortcut != NULL)
  122. return OPEN;
  123. return CLOSED;
  124. }
  125. if(entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL)
  126. return OPEN;
  127. if( entry->count > mpc->parameters.mpc_p1 &&
  128.     entry->entry_state == INGRESS_INVALID){
  129. unsigned char *ip __attribute__ ((unused)) =
  130.     (unsigned char *)&entry->ctrl_info.in_dst_ip;
  131. dprintk("mpoa: (%s) mpoa_caches.c: threshold exceeded for ip %u.%u.%u.%u, sending MPOA res reqn", mpc->dev->name, ip[0], ip[1], ip[2], ip[3]);
  132. entry->entry_state = INGRESS_RESOLVING;
  133. msg.type =  SND_MPOA_RES_RQST;
  134. memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN );
  135. msg.content.in_info = entry->ctrl_info;
  136. qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip);
  137. if (qos != NULL) msg.qos = qos->qos;
  138. msg_to_mpoad( &msg, mpc);
  139. do_gettimeofday(&(entry->reply_wait));
  140. }
  141. return CLOSED;
  142. }
  143. static void in_cache_put(in_cache_entry *entry)
  144. {
  145. if (atomic_dec_and_test(&entry->use)) {
  146. memset(entry, 0, sizeof(in_cache_entry));
  147. kfree(entry);
  148. }
  149. return;
  150. }
  151. /*
  152.  * This should be called with write lock on
  153.  */
  154. static void in_cache_remove_entry(in_cache_entry *entry,
  155.   struct mpoa_client *client)
  156. {
  157. struct atm_vcc *vcc;
  158. struct k_message msg;
  159. unsigned char *ip;
  160. vcc = entry->shortcut;
  161. ip = (unsigned char *)&entry->ctrl_info.in_dst_ip;
  162. dprintk("mpoa: mpoa_caches.c: removing an ingress entry, ip = %u.%u.%u.%un",ip[0], ip[1], ip[2], ip[3]);
  163. if (entry->prev != NULL)
  164. entry->prev->next = entry->next;
  165. else
  166. client->in_cache = entry->next;
  167. if (entry->next != NULL)
  168. entry->next->prev = entry->prev;
  169. client->in_ops->put(entry);
  170. if(client->in_cache == NULL && client->eg_cache == NULL){
  171. msg.type = STOP_KEEP_ALIVE_SM;
  172. msg_to_mpoad(&msg,client);
  173. }
  174. /* Check if the egress side still uses this VCC */
  175. if (vcc != NULL) {
  176. eg_cache_entry *eg_entry = client->eg_ops->get_by_vcc(vcc, client);
  177. if (eg_entry != NULL) {
  178. client->eg_ops->put(eg_entry);
  179. return;
  180. }
  181. atm_async_release_vcc(vcc, -EPIPE);
  182. }
  183. return;
  184. }
  185. /* Call this every MPC-p2 seconds... Not exactly correct solution,
  186.    but an easy one... */
  187. static void clear_count_and_expired(struct mpoa_client *client)
  188. {
  189. unsigned char *ip;
  190. in_cache_entry *entry, *next_entry;
  191. struct timeval now;
  192. do_gettimeofday(&now);
  193. write_lock_bh(&client->ingress_lock);
  194. entry = client->in_cache;
  195. while(entry != NULL){
  196. entry->count=0;
  197. next_entry = entry->next;
  198. if((now.tv_sec - entry->tv.tv_sec)
  199.    > entry->ctrl_info.holding_time){
  200. ip = (unsigned char*)&entry->ctrl_info.in_dst_ip;
  201. dprintk("mpoa: mpoa_caches.c: holding time expired, ip = %u.%u.%u.%un", NIPQUAD(ip));
  202. client->in_ops->remove_entry(entry, client);
  203. }
  204. entry = next_entry;
  205. }
  206. write_unlock_bh(&client->ingress_lock);
  207. return;
  208. }
  209. /* Call this every MPC-p4 seconds. */
  210. static void check_resolving_entries(struct mpoa_client *client)
  211. {
  212. struct atm_mpoa_qos *qos;
  213. in_cache_entry *entry;
  214. struct timeval now;
  215. struct k_message msg;
  216. do_gettimeofday( &now );
  217. read_lock_bh(&client->ingress_lock);
  218. entry = client->in_cache;
  219. while( entry != NULL ){
  220. if(entry->entry_state == INGRESS_RESOLVING){
  221. if(now.tv_sec - entry->hold_down.tv_sec < client->parameters.mpc_p6){
  222. entry = entry->next;                      /* Entry in hold down */
  223. continue;
  224. }
  225. if( (now.tv_sec - entry->reply_wait.tv_sec) >
  226.     entry->retry_time ){
  227. entry->retry_time = MPC_C1*( entry->retry_time );
  228. if(entry->retry_time > client->parameters.mpc_p5){
  229. /* Retry time maximum exceeded, put entry in hold down. */
  230. do_gettimeofday(&(entry->hold_down));
  231. entry->retry_time = client->parameters.mpc_p4;
  232. entry = entry->next;
  233. continue;
  234. }
  235. /* Ask daemon to send a resolution request. */
  236. memset(&(entry->hold_down),0,sizeof(struct timeval));
  237. msg.type = SND_MPOA_RES_RTRY;
  238. memcpy(msg.MPS_ctrl, client->mps_ctrl_addr, ATM_ESA_LEN);
  239. msg.content.in_info = entry->ctrl_info;
  240. qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip);
  241. if (qos != NULL) msg.qos = qos->qos;
  242. msg_to_mpoad(&msg, client);
  243. do_gettimeofday(&(entry->reply_wait));
  244. }
  245. }
  246. entry = entry->next;
  247. }
  248. read_unlock_bh(&client->ingress_lock);
  249. }
  250. /* Call this every MPC-p5 seconds. */
  251. static void refresh_entries(struct mpoa_client *client)
  252. {
  253. struct timeval now;
  254. struct in_cache_entry *entry = client->in_cache;
  255. ddprintk("mpoa: mpoa_caches.c: refresh_entriesn");
  256. do_gettimeofday(&now);
  257. read_lock_bh(&client->ingress_lock);
  258. while( entry != NULL ){
  259. if( entry->entry_state == INGRESS_RESOLVED ){
  260. if(!(entry->refresh_time))
  261. entry->refresh_time = (2*(entry->ctrl_info.holding_time))/3;
  262. if( (now.tv_sec - entry->reply_wait.tv_sec) > entry->refresh_time ){
  263. dprintk("mpoa: mpoa_caches.c: refreshing an entry.n");
  264. entry->entry_state = INGRESS_REFRESHING;
  265. }
  266. }
  267. entry = entry->next;
  268. }
  269. read_unlock_bh(&client->ingress_lock);
  270. }
  271. static void in_destroy_cache(struct mpoa_client *mpc)
  272. {
  273. write_lock_irq(&mpc->ingress_lock);
  274. while(mpc->in_cache != NULL)
  275. mpc->in_ops->remove_entry(mpc->in_cache, mpc);
  276. write_unlock_irq(&mpc->ingress_lock);
  277. return;
  278. }
  279. static eg_cache_entry *eg_cache_get_by_cache_id(uint32_t cache_id, struct mpoa_client *mpc)
  280. {
  281. eg_cache_entry *entry;
  282. read_lock_irq(&mpc->egress_lock);
  283. entry = mpc->eg_cache;
  284. while(entry != NULL){
  285. if(entry->ctrl_info.cache_id == cache_id){
  286. atomic_inc(&entry->use);
  287. read_unlock_irq(&mpc->egress_lock);
  288. return entry;
  289. }
  290. entry = entry->next;
  291. }
  292. read_unlock_irq(&mpc->egress_lock);
  293. return NULL;
  294. }
  295. /* This can be called from any context since it saves CPU flags */
  296. static eg_cache_entry *eg_cache_get_by_tag(uint32_t tag, struct mpoa_client *mpc)
  297. {
  298. unsigned long flags;
  299. eg_cache_entry *entry;
  300. read_lock_irqsave(&mpc->egress_lock, flags);
  301. entry = mpc->eg_cache;
  302. while (entry != NULL){
  303. if (entry->ctrl_info.tag == tag) {
  304. atomic_inc(&entry->use);
  305. read_unlock_irqrestore(&mpc->egress_lock, flags);
  306. return entry;
  307. }
  308. entry = entry->next;
  309. }
  310. read_unlock_irqrestore(&mpc->egress_lock, flags);
  311. return NULL;
  312. }
  313. /* This can be called from any context since it saves CPU flags */
  314. static eg_cache_entry *eg_cache_get_by_vcc(struct atm_vcc *vcc, struct mpoa_client *mpc)
  315. {
  316. unsigned long flags;
  317. eg_cache_entry *entry;
  318. read_lock_irqsave(&mpc->egress_lock, flags);
  319. entry = mpc->eg_cache;
  320. while (entry != NULL){
  321. if (entry->shortcut == vcc) {
  322. atomic_inc(&entry->use);
  323.         read_unlock_irqrestore(&mpc->egress_lock, flags);
  324. return entry;
  325. }
  326. entry = entry->next;
  327. }
  328. read_unlock_irqrestore(&mpc->egress_lock, flags);
  329. return NULL;
  330. }
  331. static eg_cache_entry *eg_cache_get_by_src_ip(uint32_t ipaddr, struct mpoa_client *mpc)
  332. {
  333. eg_cache_entry *entry;
  334. read_lock_irq(&mpc->egress_lock);
  335. entry = mpc->eg_cache;
  336. while(entry != NULL){
  337. if(entry->latest_ip_addr == ipaddr) {
  338. atomic_inc(&entry->use);
  339.         read_unlock_irq(&mpc->egress_lock);
  340. return entry;
  341. }
  342. entry = entry->next;
  343. }
  344. read_unlock_irq(&mpc->egress_lock);
  345. return NULL;
  346. }
  347. static void eg_cache_put(eg_cache_entry *entry)
  348. {
  349. if (atomic_dec_and_test(&entry->use)) {
  350. memset(entry, 0, sizeof(eg_cache_entry));
  351. kfree(entry);
  352. }
  353. return;
  354. }
  355. /*
  356.  * This should be called with write lock on
  357.  */
  358. static void eg_cache_remove_entry(eg_cache_entry *entry,
  359.   struct mpoa_client *client)
  360. {
  361. struct atm_vcc *vcc;
  362. struct k_message msg;
  363. vcc = entry->shortcut;
  364. dprintk("mpoa: mpoa_caches.c: removing an egress entry.n");
  365. if (entry->prev != NULL)
  366. entry->prev->next = entry->next;
  367. else
  368. client->eg_cache = entry->next;
  369. if (entry->next != NULL)
  370. entry->next->prev = entry->prev;
  371. client->eg_ops->put(entry);
  372. if(client->in_cache == NULL && client->eg_cache == NULL){
  373. msg.type = STOP_KEEP_ALIVE_SM;
  374. msg_to_mpoad(&msg,client);
  375. }
  376. /* Check if the ingress side still uses this VCC */
  377. if (vcc != NULL) {
  378. in_cache_entry *in_entry = client->in_ops->get_by_vcc(vcc, client);
  379. if (in_entry != NULL) {
  380. client->in_ops->put(in_entry);
  381. return;
  382. }
  383. atm_async_release_vcc(vcc, -EPIPE);
  384. }
  385. return;
  386. }
  387. static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, struct mpoa_client *client)
  388. {
  389. unsigned char *ip;
  390. eg_cache_entry *entry = kmalloc(sizeof(eg_cache_entry), GFP_KERNEL);
  391. if (entry == NULL) {
  392. printk("mpoa: mpoa_caches.c: new_eg_cache_entry: out of memoryn");
  393. return NULL;
  394. }
  395. ip = (unsigned char *)&msg->content.eg_info.eg_dst_ip;
  396. dprintk("mpoa: mpoa_caches.c: adding an egress entry, ip = %u.%u.%u.%u, this should be our IPn", NIPQUAD(ip));
  397. memset(entry, 0, sizeof(eg_cache_entry));
  398. atomic_set(&entry->use, 1);
  399. dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry: about to lockn");
  400. write_lock_irq(&client->egress_lock);
  401. entry->next = client->eg_cache;
  402. entry->prev = NULL;
  403. if (client->eg_cache != NULL)
  404. client->eg_cache->prev = entry;
  405. client->eg_cache = entry;
  406. memcpy(entry->MPS_ctrl_ATM_addr, client->mps_ctrl_addr, ATM_ESA_LEN);
  407. entry->ctrl_info = msg->content.eg_info;
  408. do_gettimeofday(&(entry->tv));
  409. entry->entry_state = EGRESS_RESOLVED;
  410. dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry cache_id %lun", ntohl(entry->ctrl_info.cache_id));
  411. ip = (unsigned char *)&entry->ctrl_info.mps_ip;
  412. dprintk("mpoa: mpoa_caches.c: mps_ip = %u.%u.%u.%un", NIPQUAD(ip));
  413. atomic_inc(&entry->use);
  414. write_unlock_irq(&client->egress_lock);
  415. dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry: unlockedn");
  416. return entry;
  417. }
  418. static void update_eg_cache_entry(eg_cache_entry * entry, uint16_t holding_time)
  419. {
  420. do_gettimeofday(&(entry->tv));
  421. entry->entry_state = EGRESS_RESOLVED;
  422. entry->ctrl_info.holding_time = holding_time;
  423. return;
  424. }
  425. static void clear_expired(struct mpoa_client *client)
  426. {
  427. eg_cache_entry *entry, *next_entry;
  428. struct timeval now;
  429. struct k_message msg;
  430. do_gettimeofday(&now);
  431. write_lock_irq(&client->egress_lock);
  432. entry = client->eg_cache;
  433. while(entry != NULL){
  434. next_entry = entry->next;
  435. if((now.tv_sec - entry->tv.tv_sec)
  436.    > entry->ctrl_info.holding_time){
  437. msg.type = SND_EGRESS_PURGE;
  438. msg.content.eg_info = entry->ctrl_info;
  439. dprintk("mpoa: mpoa_caches.c: egress_cache: holding time expired, cache_id = %lu.n",ntohl(entry->ctrl_info.cache_id));
  440. msg_to_mpoad(&msg, client);
  441. client->eg_ops->remove_entry(entry, client);
  442. }
  443. entry = next_entry;
  444. }
  445. write_unlock_irq(&client->egress_lock);
  446. return;
  447. }
  448. static void eg_destroy_cache(struct mpoa_client *mpc)
  449. {
  450. write_lock_irq(&mpc->egress_lock);
  451. while(mpc->eg_cache != NULL)
  452. mpc->eg_ops->remove_entry(mpc->eg_cache, mpc);
  453. write_unlock_irq(&mpc->egress_lock);
  454. return;
  455. }
  456. static struct in_cache_ops ingress_ops = {
  457. in_cache_add_entry,               /* add_entry       */
  458. in_cache_get,                     /* get             */
  459. in_cache_get_with_mask,           /* get_with_mask   */
  460. in_cache_get_by_vcc,              /* get_by_vcc      */
  461. in_cache_put,                     /* put             */
  462. in_cache_remove_entry,            /* remove_entry    */
  463. cache_hit,                        /* cache_hit       */
  464. clear_count_and_expired,          /* clear_count     */
  465. check_resolving_entries,          /* check_resolving */
  466. refresh_entries,                  /* refresh         */
  467. in_destroy_cache                  /* destroy_cache   */
  468. };
  469. static struct eg_cache_ops egress_ops = {
  470. eg_cache_add_entry,               /* add_entry        */
  471. eg_cache_get_by_cache_id,         /* get_by_cache_id  */
  472. eg_cache_get_by_tag,              /* get_by_tag       */
  473. eg_cache_get_by_vcc,              /* get_by_vcc       */
  474. eg_cache_get_by_src_ip,           /* get_by_src_ip    */
  475. eg_cache_put,                     /* put              */
  476. eg_cache_remove_entry,            /* remove_entry     */
  477. update_eg_cache_entry,            /* update           */
  478. clear_expired,                    /* clear_expired    */
  479. eg_destroy_cache                  /* destroy_cache    */
  480. };
  481. void atm_mpoa_init_cache(struct mpoa_client *mpc)
  482. {
  483. mpc->in_ops = &ingress_ops;
  484. mpc->eg_ops = &egress_ops;
  485. return;
  486. }