|
|
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 */ 1.1.1.5 ! root 318: static int ilt_dump(char *table_name,insn_lookup_t *ilt) 1.1.1.4 root 319: { 320: rfc_array_t *rfct; 1.1.1.5 ! root 321: char *filename; ! 322: FILE *fd; 1.1.1.4 root 323: int i,j; 324: 1.1.1.5 ! root 325: filename = dyn_sprintf("ilt_dump_%s_%s.txt",sw_version_tag,table_name); ! 326: assert(filename != NULL); ! 327: ! 328: fd = fopen(filename,"w"); ! 329: assert(fd != NULL); ! 330: ! 331: fprintf(fd,"ILT %p: nr_insn=%d, cbm_size=%d\n", ! 332: ilt,ilt->nr_insn,ilt->cbm_size); 1.1.1.4 root 333: 334: for(i=0;i<RFC_ARRAY_NUMBER;i++) { 335: rfct = ilt->rfct[i]; 336: 1.1.1.5 ! root 337: fprintf(fd,"RFCT %d: nr_elements=%d, nr_eqid=%d\n", ! 338: i,rfct->nr_elements,rfct->nr_eqid); ! 339: 1.1.1.4 root 340: for(j=0;j<rfct->nr_elements;j++) 1.1.1.5 ! root 341: fprintf(fd," (0x%4.4x,0x%4.4x) = 0x%4.4x\n",i,j,rfct->eqID[j]); 1.1.1.4 root 342: } 1.1.1.5 ! root 343: ! 344: fclose(fd); ! 345: return(0); 1.1.1.4 root 346: } 347: 348: /* Write the specified RFC array to disk */ 349: static void ilt_store_rfct(FILE *fd,int id,rfc_array_t *rfct) 350: { 351: /* Store RFC array ID + number of elements */ 352: fwrite(&id,sizeof(id),1,fd); 353: fwrite(&rfct->nr_elements,sizeof(rfct->nr_elements),1,fd); 354: fwrite(&rfct->nr_eqid,sizeof(rfct->nr_eqid),1,fd); 355: 1.1.1.5 ! root 356: fwrite(rfct->eqID,sizeof(int),rfct->nr_elements,fd); 1.1.1.4 root 357: } 358: 359: /* Write the full instruction lookup table */ 360: static void ilt_store_table(FILE *fd,insn_lookup_t *ilt) 361: { 362: int i; 363: 364: for(i=0;i<RFC_ARRAY_NUMBER;i++) 365: if (ilt->rfct[i] != NULL) 366: ilt_store_rfct(fd,i,ilt->rfct[i]); 367: } 368: 369: /* Load an RFC array from disk */ 370: static int ilt_load_rfct(FILE *fd,insn_lookup_t *ilt) 371: { 372: u_int id,nr_elements,nr_eqid; 373: rfc_array_t *rfct; 374: size_t len; 375: 376: /* Read ID and number of elements */ 377: if ((fread(&id,sizeof(id),1,fd) != 1) || 378: (fread(&nr_elements,sizeof(nr_elements),1,fd) != 1) || 379: (fread(&nr_eqid,sizeof(nr_eqid),1,fd) != 1)) 380: return(-1); 1.1.1.5 ! root 381: 1.1.1.4 root 382: if ((id >= RFC_ARRAY_NUMBER) || (nr_elements > RFC_ARRAY_MAXSIZE)) 383: return(-1); 384: 385: /* Allocate the RFC array with the eqID table */ 386: len = sizeof(*rfct) + (nr_elements * sizeof(int)); 387: 388: if (!(rfct = malloc(len))) 389: return(-1); 390: 391: memset(rfct,0,sizeof(*rfct)); 392: rfct->nr_elements = nr_elements; 393: rfct->nr_eqid = nr_eqid; 1.1.1.5 ! root 394: 1.1.1.4 root 395: /* Read the equivalent ID array */ 1.1.1.5 ! root 396: if (fread(rfct->eqID,sizeof(int),nr_elements,fd) != nr_elements) { ! 397: free(rfct); ! 398: return(-1); ! 399: } 1.1.1.4 root 400: 401: ilt->rfct[id] = rfct; 402: return(0); 403: } 404: 405: /* Check an instruction table loaded from disk */ 406: static int ilt_check_cached_table(insn_lookup_t *ilt) 407: { 408: int i; 409: 410: /* All arrays must have been loaded */ 411: for(i=0;i<RFC_ARRAY_NUMBER;i++) 412: if (!ilt->rfct[i]) 413: return(-1); 414: 415: return(0); 416: } 417: 418: /* Load a full instruction table from disk */ 419: static insn_lookup_t *ilt_load_table(FILE *fd) 420: { 421: insn_lookup_t *ilt; 1.1.1.5 ! root 422: int i; ! 423: 1.1.1.4 root 424: if (!(ilt = malloc(sizeof(*ilt)))) 425: return NULL; 426: 427: memset(ilt,0,sizeof(*ilt)); 1.1.1.5 ! root 428: fseek(fd,0,SEEK_SET); 1.1.1.4 root 429: 1.1.1.5 ! root 430: for(i=0;i<RFC_ARRAY_NUMBER;i++) { 1.1.1.4 root 431: if (ilt_load_rfct(fd,ilt) == -1) 1.1.1.5 ! root 432: return NULL; 1.1.1.4 root 433: } 434: 435: if (ilt_check_cached_table(ilt) == -1) 436: return NULL; 437: 438: return ilt; 439: } 440: 441: /* Build a filename for a cached ILT table on disk */ 442: static char *ilt_build_filename(char *table_name) 443: { 444: return(dyn_sprintf("ilt_%s_%s",sw_version_tag,table_name)); 445: } 446: 447: /* Try to load a cached ILT table from disk */ 448: static insn_lookup_t *ilt_cache_load(char *table_name) 449: { 450: insn_lookup_t *ilt; 451: char *filename; 452: FILE *fd; 453: 454: if (!(filename = ilt_build_filename(table_name))) 455: return NULL; 456: 1.1.1.5 ! root 457: if (!(fd = fopen(filename,"rb"))) { 1.1.1.4 root 458: free(filename); 459: return NULL; 460: } 461: 462: ilt = ilt_load_table(fd); 463: fclose(fd); 464: return ilt; 465: } 466: 467: /* Store the specified ILT table on disk for future use (cache) */ 468: static int ilt_cache_store(char *table_name,insn_lookup_t *ilt) 469: { 470: char *filename; 471: FILE *fd; 472: 473: if (!(filename = ilt_build_filename(table_name))) 474: return(-1); 475: 1.1.1.5 ! root 476: if (!(fd = fopen(filename,"wb"))) { 1.1.1.4 root 477: free(filename); 478: return(-1); 479: } 480: 481: ilt_store_table(fd,ilt); 482: fclose(fd); 1.1.1.5 ! root 483: free(filename); 1.1.1.4 root 484: return(0); 485: } 486: 1.1 root 487: /* Create an instruction lookup table */ 1.1.1.4 root 488: insn_lookup_t *ilt_create(char *table_name, 489: int nr_insn,ilt_get_insn_cbk_t get_insn, 1.1 root 490: ilt_check_cbk_t chk_lo,ilt_check_cbk_t chk_hi) 491: { 492: insn_lookup_t *ilt; 493: 1.1.1.4 root 494: /* Try to load a cached table from disk */ 495: if ((ilt = ilt_cache_load(table_name))) { 496: printf("ILT: loaded table \"%s\" from cache.\n",table_name); 497: return ilt; 498: } 499: 500: /* We have to build the full table... */ 1.1.1.2 root 501: ilt = malloc(sizeof(*ilt)); 502: assert(ilt); 1.1 root 503: memset(ilt,0,sizeof(*ilt)); 504: 505: ilt->cbm_size = normalize_size(nr_insn,CBM_SIZE,CBM_SHIFT); 506: ilt->nr_insn = nr_insn; 507: ilt->get_insn = get_insn; 508: ilt->chk_lo = chk_lo; 509: ilt->chk_hi = chk_hi; 510: 1.1.1.4 root 511: /* Compile the instruction opcodes */ 1.1 root 512: ilt_compile(ilt); 1.1.1.4 root 513: 514: /* Store the result on disk for future exec */ 515: ilt_cache_store(table_name,ilt); 1.1 root 516: return(ilt); 517: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.