|
|
1.1 root 1: /* 1.1.1.3 root 2: * Cisco router simulation platform. 1.1 root 3: * Copyright (c) 2006 Christophe Fillot ([email protected]) 4: * 5: * Instruction Lookup Tables. 6: */ 7: 8: #include <stdio.h> 9: #include <stdlib.h> 10: #include <unistd.h> 11: #include <string.h> 12: #include <sys/types.h> 13: #include <sys/stat.h> 14: #include <sys/mman.h> 15: #include <assert.h> 16: 17: #include "utils.h" 18: #include "hash.h" 19: #include "insn_lookup.h" 1.1.1.4 ! root 20: #include "dynamips.h" 1.1 root 21: 22: /* Hash function for a CBM */ 23: static inline u_int cbm_hash_f(void *ccbm) 24: { 25: cbm_array_t *cbm = (cbm_array_t *)ccbm; 26: char *p,*s = (char *)(cbm->tab); 27: u_int h,g,i; 28: 29: for(h=0,i=0,p=s;i<(cbm->nr_entries*sizeof(int));p+=1,i++) 30: { 31: h = (h << 4) + *p; 32: if ((g = h & 0xf0000000)) { 33: h = h ^ (g >> 24); 34: h = h ^ g; 35: } 36: } 37: 38: return(h); 39: } 40: 41: /* Comparison function for 2 CBM */ 42: static inline int cbm_cmp_f(void *b1,void *b2) 43: { 44: cbm_array_t *cbm1 = (cbm_array_t *)b1; 45: cbm_array_t *cbm2 = (cbm_array_t *)b2; 46: int i; 47: 48: for(i=0;i<cbm1->nr_entries;i++) 49: if (cbm1->tab[i] != cbm2->tab[i]) 50: return(FALSE); 51: 52: return(TRUE); 53: } 54: 55: /* Set bit corresponding to a rule number in a CBM */ 56: static inline void cbm_set_rule(cbm_array_t *cbm,int rule_id) 57: { 58: CBM_ARRAY(cbm,(rule_id >> CBM_SHIFT)) |= 1 << (rule_id & (CBM_SIZE-1)); 59: } 60: 61: /* Clear bit corresponding to a rule number in a CBM */ 62: static inline void cbm_unset_rule(cbm_array_t *cbm,int rule_id) 63: { 64: CBM_ARRAY(cbm,(rule_id >> CBM_SHIFT)) &= ~(1 << (rule_id & (CBM_SIZE-1))); 65: } 66: 67: /* Returns TRUE if bit corresponding to a rule number in a CBM is set */ 68: static inline int cbm_check_rule(cbm_array_t *cbm,int rule_id) 69: { 70: return(CBM_ARRAY(cbm,(rule_id >> CBM_SHIFT)) & 71: (1 << (rule_id & (CBM_SIZE-1)))); 72: } 73: 74: /* Compute bitwise ANDing of two CBM */ 75: static inline void 76: cbm_bitwise_and(cbm_array_t *result,cbm_array_t *a1,cbm_array_t *a2) 77: { 78: int i; 79: 80: /* Compute bitwise ANDing */ 81: for(i=0;i<a1->nr_entries;i++) 82: CBM_ARRAY(result,i) = CBM_ARRAY(a1,i) & CBM_ARRAY(a2,i); 83: } 84: 85: /* Get first matching rule number */ 86: static inline int cbm_first_match(insn_lookup_t *ilt,cbm_array_t *cbm) 87: { 88: int i; 89: 90: for(i=0;i<ilt->nr_insn;i++) 91: if (cbm_check_rule(cbm,i)) 92: return(i); 93: 94: return(-1); 95: } 96: 97: /* Create a class bitmap (CBM) */ 98: static cbm_array_t *cbm_create(insn_lookup_t *ilt) 99: { 100: cbm_array_t *array; 101: int size; 102: 103: size = CBM_CSIZE(ilt->cbm_size); 104: 105: /* CBM are simply bit arrays */ 1.1.1.2 root 106: array = malloc(size); 107: assert(array); 108: 1.1 root 109: memset(array,0,size); 110: array->nr_entries = ilt->cbm_size; 111: return array; 112: } 113: 114: /* Duplicate a class bitmap */ 115: static cbm_array_t *cbm_duplicate(cbm_array_t *cbm) 116: { 117: int size = CBM_CSIZE(cbm->nr_entries); 118: cbm_array_t *array; 119: 1.1.1.2 root 120: array = malloc(size); 121: assert(array); 1.1 root 122: memcpy(array,cbm,size); 123: return array; 124: } 125: 126: /* 127: * Get equivalent class corresponding to a class bitmap. Create eqclass 128: * structure if needed (CBM not previously seen). 129: */ 130: static rfc_eqclass_t *cbm_get_eqclass(rfc_array_t *rfct,cbm_array_t *cbm) 131: { 132: rfc_eqclass_t *eqcl; 133: cbm_array_t *bmp; 134: 135: /* Lookup for CBM into hash table */ 136: if ((eqcl = hash_table_lookup(rfct->cbm_hash,cbm)) == NULL) 137: { 138: /* Duplicate CBM */ 1.1.1.2 root 139: bmp = cbm_duplicate(cbm); 140: assert(bmp); 1.1 root 141: 142: /* CBM is not already known */ 1.1.1.2 root 143: eqcl = malloc(sizeof(rfc_eqclass_t)); 144: assert(eqcl); 145: 1.1 root 146: assert(rfct->nr_eqid < rfct->nr_elements); 147: 148: /* Get a new equivalent ID */ 149: eqcl->eqID = rfct->nr_eqid++; 150: eqcl->cbm = bmp; 151: rfct->id2cbm[eqcl->eqID] = bmp; 152: 153: /* Insert it in hash table */ 1.1.1.2 root 154: if (hash_table_insert(rfct->cbm_hash,bmp,eqcl) == -1) 155: return NULL; 1.1 root 156: } 157: 158: return eqcl; 159: } 160: 161: /* Allocate an array for Recursive Flow Classification */ 162: static rfc_array_t *rfc_alloc_array(int nr_elements) 163: { 164: rfc_array_t *array; 165: int total_size; 166: 167: /* Compute size of memory chunk needed to store the array */ 168: total_size = (nr_elements * sizeof(int)) + sizeof(rfc_array_t); 1.1.1.2 root 169: array = malloc(total_size); 170: assert(array); 1.1 root 171: memset(array,0,total_size); 172: array->nr_elements = nr_elements; 173: 174: /* Initialize hash table for Class Bitmaps */ 175: array->cbm_hash = hash_table_create(cbm_hash_f,cbm_cmp_f,CBM_HASH_SIZE); 1.1.1.2 root 176: assert(array->cbm_hash); 1.1 root 177: 178: /* Initialize table for converting ID to CBM */ 179: array->id2cbm = calloc(nr_elements,sizeof(cbm_array_t *)); 1.1.1.2 root 180: assert(array->id2cbm); 1.1 root 181: 182: return(array); 183: } 184: 185: /* Check an instruction with specified parameter */ 186: static void rfc_check_insn(insn_lookup_t *ilt,cbm_array_t *cbm, 187: ilt_check_cbk_t pcheck,int value) 188: { 189: void *p; 190: int i; 191: 192: for(i=0;i<ilt->nr_insn;i++) { 193: p = ilt->get_insn(i); 194: 195: if (pcheck(p,value)) 196: cbm_set_rule(cbm,i); 197: else 198: cbm_unset_rule(cbm,i); 199: } 200: } 201: 202: /* RFC Chunk preprocessing: phase 0 */ 203: static rfc_array_t *rfc_phase_0(insn_lookup_t *ilt,ilt_check_cbk_t pcheck) 204: { 205: rfc_eqclass_t *eqcl; 206: rfc_array_t *rfct; 207: cbm_array_t *bmp; 208: int i; 209: 210: /* allocate a temporary class bitmap */ 1.1.1.2 root 211: bmp = cbm_create(ilt); 212: assert(bmp); 1.1 root 213: 214: /* Allocate a new RFC array of 16-bits entries */ 1.1.1.2 root 215: rfct = rfc_alloc_array(RFC_ARRAY_MAXSIZE); 216: assert(rfct); 1.1 root 217: 218: for(i=0;i<RFC_ARRAY_MAXSIZE;i++) 219: { 220: /* determine all instructions that match this value */ 221: rfc_check_insn(ilt,bmp,pcheck,i); 222: 223: /* get equivalent class for this bitmap */ 1.1.1.2 root 224: eqcl = cbm_get_eqclass(rfct,bmp); 225: assert(eqcl); 1.1 root 226: 227: /* fill the RFC table */ 228: rfct->eqID[i] = eqcl->eqID; 229: } 230: 231: free(bmp); 232: return rfct; 233: } 234: 235: /* RFC Chunk preprocessing: phase j (j > 0) */ 236: static rfc_array_t *rfc_phase_j(insn_lookup_t *ilt,rfc_array_t *p0, 237: rfc_array_t *p1) 238: { 239: rfc_eqclass_t *eqcl; 240: rfc_array_t *rfct; 241: cbm_array_t *bmp; 242: int nr_elements; 243: int index = 0; 244: int i,j; 245: 246: /* allocate a temporary class bitmap */ 1.1.1.2 root 247: bmp = cbm_create(ilt); 248: assert(bmp); 1.1 root 249: 250: /* compute number of elements */ 251: nr_elements = p0->nr_eqid * p1->nr_eqid; 252: 253: /* allocate a new RFC array */ 1.1.1.2 root 254: rfct = rfc_alloc_array(nr_elements); 255: assert(rfct); 1.1 root 256: rfct->parent0 = p0; 257: rfct->parent1 = p1; 258: 259: /* make a cross product between p0 and p1 */ 260: for(i=0;i<p0->nr_eqid;i++) 261: for(j=0;j<p1->nr_eqid;j++) 262: { 263: /* compute bitwise AND */ 264: cbm_bitwise_and(bmp,p0->id2cbm[i],p1->id2cbm[j]); 265: 266: /* get equivalent class for this bitmap */ 1.1.1.2 root 267: eqcl = cbm_get_eqclass(rfct,bmp); 268: assert(eqcl); 1.1 root 269: 270: /* fill RFC table */ 271: rfct->eqID[index++] = eqcl->eqID; 272: } 273: 274: free(bmp); 275: return rfct; 276: } 277: 278: /* Compute RFC phase 0 */ 279: static void ilt_phase_0(insn_lookup_t *ilt,int idx,ilt_check_cbk_t pcheck) 280: { 281: rfc_array_t *rfct; 282: 1.1.1.2 root 283: rfct = rfc_phase_0(ilt,pcheck); 284: assert(rfct); 1.1 root 285: ilt->rfct[idx] = rfct; 286: } 287: 288: /* Compute RFC phase j */ 289: static void ilt_phase_j(insn_lookup_t *ilt,int p0,int p1,int res) 290: { 291: rfc_array_t *rfct; 292: 1.1.1.2 root 293: rfct = rfc_phase_j(ilt,ilt->rfct[p0],ilt->rfct[p1]); 294: assert(rfct); 1.1 root 295: ilt->rfct[res] = rfct; 296: } 297: 298: /* Postprocessing */ 299: static void ilt_postprocessing(insn_lookup_t *ilt) 300: { 301: rfc_array_t *rfct = ilt->rfct[2]; 302: int i; 303: 304: for(i=0;i<rfct->nr_elements;i++) 305: rfct->eqID[i] = cbm_first_match(ilt,rfct->id2cbm[rfct->eqID[i]]); 306: } 307: 308: /* Instruction lookup table compilation */ 309: static void ilt_compile(insn_lookup_t *ilt) 310: { 311: ilt_phase_0(ilt,0,ilt->chk_hi); 312: ilt_phase_0(ilt,1,ilt->chk_lo); 313: ilt_phase_j(ilt,0,1,2); 314: ilt_postprocessing(ilt); 315: } 316: 1.1.1.4 ! root 317: /* Dump an instruction lookup table */ ! 318: static void ilt_dump(insn_lookup_t *ilt) ! 319: { ! 320: rfc_array_t *rfct; ! 321: int i,j; ! 322: ! 323: printf("ILT %p: nr_insn=%d, cbm_size=%d\n",ilt,ilt->nr_insn,ilt->cbm_size); ! 324: ! 325: for(i=0;i<RFC_ARRAY_NUMBER;i++) { ! 326: rfct = ilt->rfct[i]; ! 327: ! 328: for(j=0;j<rfct->nr_elements;j++) ! 329: printf(" (0x%4.4x,0x%4.4x) = 0x%4.4x\n",i,j,rfct->eqID[j]); ! 330: } ! 331: } ! 332: ! 333: /* Write the specified RFC array to disk */ ! 334: static void ilt_store_rfct(FILE *fd,int id,rfc_array_t *rfct) ! 335: { ! 336: /* Store RFC array ID + number of elements */ ! 337: fwrite(&id,sizeof(id),1,fd); ! 338: fwrite(&rfct->nr_elements,sizeof(rfct->nr_elements),1,fd); ! 339: fwrite(&rfct->nr_eqid,sizeof(rfct->nr_eqid),1,fd); ! 340: ! 341: fwrite(rfct->eqID,rfct->nr_elements,sizeof(int),fd); ! 342: } ! 343: ! 344: /* Write the full instruction lookup table */ ! 345: static void ilt_store_table(FILE *fd,insn_lookup_t *ilt) ! 346: { ! 347: int i; ! 348: ! 349: for(i=0;i<RFC_ARRAY_NUMBER;i++) ! 350: if (ilt->rfct[i] != NULL) ! 351: ilt_store_rfct(fd,i,ilt->rfct[i]); ! 352: } ! 353: ! 354: /* Load an RFC array from disk */ ! 355: static int ilt_load_rfct(FILE *fd,insn_lookup_t *ilt) ! 356: { ! 357: u_int id,nr_elements,nr_eqid; ! 358: rfc_array_t *rfct; ! 359: size_t len; ! 360: ! 361: /* Read ID and number of elements */ ! 362: if ((fread(&id,sizeof(id),1,fd) != 1) || ! 363: (fread(&nr_elements,sizeof(nr_elements),1,fd) != 1) || ! 364: (fread(&nr_eqid,sizeof(nr_eqid),1,fd) != 1)) ! 365: return(-1); ! 366: ! 367: if ((id >= RFC_ARRAY_NUMBER) || (nr_elements > RFC_ARRAY_MAXSIZE)) ! 368: return(-1); ! 369: ! 370: /* Allocate the RFC array with the eqID table */ ! 371: len = sizeof(*rfct) + (nr_elements * sizeof(int)); ! 372: ! 373: if (!(rfct = malloc(len))) ! 374: return(-1); ! 375: ! 376: memset(rfct,0,sizeof(*rfct)); ! 377: rfct->nr_elements = nr_elements; ! 378: rfct->nr_eqid = nr_eqid; ! 379: ! 380: /* Read the equivalent ID array */ ! 381: fread(rfct->eqID,rfct->nr_elements,sizeof(int),fd); ! 382: ! 383: ilt->rfct[id] = rfct; ! 384: return(0); ! 385: } ! 386: ! 387: /* Check an instruction table loaded from disk */ ! 388: static int ilt_check_cached_table(insn_lookup_t *ilt) ! 389: { ! 390: int i; ! 391: ! 392: /* All arrays must have been loaded */ ! 393: for(i=0;i<RFC_ARRAY_NUMBER;i++) ! 394: if (!ilt->rfct[i]) ! 395: return(-1); ! 396: ! 397: return(0); ! 398: } ! 399: ! 400: /* Load a full instruction table from disk */ ! 401: static insn_lookup_t *ilt_load_table(FILE *fd) ! 402: { ! 403: insn_lookup_t *ilt; ! 404: ! 405: if (!(ilt = malloc(sizeof(*ilt)))) ! 406: return NULL; ! 407: ! 408: memset(ilt,0,sizeof(*ilt)); ! 409: ! 410: while(!feof(fd)) { ! 411: if (ilt_load_rfct(fd,ilt) == -1) ! 412: break; ! 413: } ! 414: ! 415: if (ilt_check_cached_table(ilt) == -1) ! 416: return NULL; ! 417: ! 418: return ilt; ! 419: } ! 420: ! 421: /* Build a filename for a cached ILT table on disk */ ! 422: static char *ilt_build_filename(char *table_name) ! 423: { ! 424: return(dyn_sprintf("ilt_%s_%s",sw_version_tag,table_name)); ! 425: } ! 426: ! 427: /* Try to load a cached ILT table from disk */ ! 428: static insn_lookup_t *ilt_cache_load(char *table_name) ! 429: { ! 430: insn_lookup_t *ilt; ! 431: char *filename; ! 432: FILE *fd; ! 433: ! 434: if (!(filename = ilt_build_filename(table_name))) ! 435: return NULL; ! 436: ! 437: if (!(fd = fopen(filename,"r"))) { ! 438: free(filename); ! 439: return NULL; ! 440: } ! 441: ! 442: ilt = ilt_load_table(fd); ! 443: fclose(fd); ! 444: return ilt; ! 445: } ! 446: ! 447: /* Store the specified ILT table on disk for future use (cache) */ ! 448: static int ilt_cache_store(char *table_name,insn_lookup_t *ilt) ! 449: { ! 450: char *filename; ! 451: FILE *fd; ! 452: ! 453: if (!(filename = ilt_build_filename(table_name))) ! 454: return(-1); ! 455: ! 456: if (!(fd = fopen(filename,"w"))) { ! 457: free(filename); ! 458: return(-1); ! 459: } ! 460: ! 461: ilt_store_table(fd,ilt); ! 462: fclose(fd); ! 463: return(0); ! 464: } ! 465: 1.1 root 466: /* Create an instruction lookup table */ 1.1.1.4 ! root 467: insn_lookup_t *ilt_create(char *table_name, ! 468: int nr_insn,ilt_get_insn_cbk_t get_insn, 1.1 root 469: ilt_check_cbk_t chk_lo,ilt_check_cbk_t chk_hi) 470: { 471: insn_lookup_t *ilt; 472: 1.1.1.4 ! root 473: /* Try to load a cached table from disk */ ! 474: if ((ilt = ilt_cache_load(table_name))) { ! 475: printf("ILT: loaded table \"%s\" from cache.\n",table_name); ! 476: return ilt; ! 477: } ! 478: ! 479: /* We have to build the full table... */ 1.1.1.2 root 480: ilt = malloc(sizeof(*ilt)); 481: assert(ilt); 1.1 root 482: memset(ilt,0,sizeof(*ilt)); 483: 484: ilt->cbm_size = normalize_size(nr_insn,CBM_SIZE,CBM_SHIFT); 485: ilt->nr_insn = nr_insn; 486: ilt->get_insn = get_insn; 487: ilt->chk_lo = chk_lo; 488: ilt->chk_hi = chk_hi; 489: 1.1.1.4 ! root 490: /* Compile the instruction opcodes */ 1.1 root 491: ilt_compile(ilt); 1.1.1.4 ! root 492: ! 493: /* Store the result on disk for future exec */ ! 494: ilt_cache_store(table_name,ilt); 1.1 root 495: return(ilt); 496: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.