static ucli_status_t ppe_ucli_utm__format__(ucli_context_t* uc) { ppe_header_t header; UCLI_COMMAND_INFO(uc, "format", 1, "Change the format of the current packet."); UCLI_ARGPARSE_OR_RETURN(uc, "{ppe_header}", &header); if(header == PPE_HEADER_8021Q || header == PPE_HEADER_ETHERII) { int rv; rv = ppe_packet_format_set(&ppec->ppep, header); if(rv < 0) { return ucli_error(uc, "packet format conversion failed."); } if(rv == 1) { aim_free(ppec->ppep._data); } } else { return ucli_error(uc, "%{ppe_header} is not a valid conversion.", header); } return UCLI_STATUS_OK; }
static ucli_status_t ppe_ucli_utm__checkw__(ucli_context_t* uc) { ppe_field_info_t* fi; uint8_t* cvalue; uint8_t pvalue[128]; unsigned int csize; aim_datatype_map_t* operation; aim_datatype_map_t operation_map[] = { { "==", 'e' }, { "!=", 'n' }, { NULL } }; UCLI_COMMAND_INFO(uc, "checkw", 3, "Check wide packet field values and status."); UCLI_ARGPARSE_OR_RETURN(uc, "{ppe_field_info}{map}{data}", &fi, &operation, operation_map, "operation", &cvalue, &csize); PPE_FIELD_EXISTS_OR_RETURN(uc, fi->field); if(fi->size_bits/8 != csize) { return ucli_error(uc, "field %{ppe_field} is %d bytes wide.", fi->field, fi->size_bits/8); } PPE_WIDE_FIELD_GET_OR_RETURN(uc, &ppec->ppep, fi->field, pvalue); switch(operation->i) { case 'e': { if(PPE_MEMCMP(pvalue, cvalue, csize)) { return ucli_error(uc, "field %{ppe_field} is %{data} (should be %{data}", fi->field, pvalue, csize, cvalue, csize); } return UCLI_STATUS_OK; break; } case 'n': { if(!PPE_MEMCMP(pvalue, cvalue, csize)) { return ucli_error(uc, "field %{ppe_field} is %{data}", fi->field, pvalue, csize); } return UCLI_STATUS_OK; break; } default: return ucli_e_internal(uc, "unknown operation."); } }
static ucli_status_t ppe_ucli_utm__check__(ucli_context_t* uc) { ppe_field_info_t* fi; uint32_t cvalue; uint32_t pvalue; aim_datatype_map_t* operation; aim_datatype_map_t operation_map[] = { { "==", 'e' }, { "!=", 'n' }, { NULL } }; UCLI_COMMAND_INFO(uc, "check", 3, "Check packet field values and status."); UCLI_ARGPARSE_OR_RETURN(uc, "{ppe_field_info}{map}i", &fi, &operation, operation_map, "operation", &cvalue); PPE_FIELD_EXISTS_OR_RETURN(uc, fi->field); PPE_FIELD32_OR_RETURN(uc, fi->size_bits); PPE_FIELD_GET_OR_RETURN(uc, &ppec->ppep, fi->field, &pvalue); switch(operation->i) { case 'e': { if(pvalue != cvalue) { return ucli_error(uc, "field %{ppe_field} is 0x%x (%d) (should be 0x%x (%d)", fi->field, pvalue, pvalue, cvalue, cvalue); } return UCLI_STATUS_OK; break; } case 'n': { if(pvalue == cvalue) { return ucli_error(uc, "field %{ppe_field} is 0x%x (%d)", fi->field, pvalue, pvalue); } return UCLI_STATUS_OK; break; } default: return ucli_e_internal(uc, "unknown operation."); } }
static ucli_status_t fme_ucli_utm__key__(ucli_context_t* uc) { uint32_t keymask; uint8_t* value = NULL; int value_size = 0; uint8_t* mask = NULL; int mask_size = 0; int rv = UCLI_STATUS_OK; fme_key_t key; UCLI_COMMAND_INFO(uc, "key", 3, "Set the match key for the current entry."); UCLI_ARGPARSE_OR_RETURN(uc, "i{data}{data}", &keymask, &value, &value_size, &mask, &mask_size); if(value_size != mask_size) { rv = ucli_error(uc, "value size (%d) and mask size (%d) must be equal.", value_size, mask_size); goto __key__error; } if(value_size % 4 != 0) { rv = ucli_error(uc, "values and masks must be 32bit aligned (size=%d)", value_size); goto __key__error; } FME_MEMSET(&key, 0, sizeof(key)); key.keymask = keymask; key.size = value_size; FME_MEMCPY(key.values, value, value_size); FME_MEMCPY(key.masks, mask, mask_size); aim_free(value); aim_free(mask); fme_entry_key_set(fmec->entries[fmec->eid], &key); return rv; __key__error: aim_free(value); aim_free(mask); return rv; }
ucli_status_t vt_ucli_module__echo__(ucli_context_t* uc) { UCLI_COMMAND_INFO(uc, "echo", 2, "$summary#Send a VPI echo request." "$args#<vpi_spec> <data>"); UCLI_ARGPARSE_OR_RETURN(uc, "{vpi}{idata}", &vtc->vpi, vtc->data, &vtc->size); ucli_printf(uc, "sending echo request.\n"); if(vpi_ioctl(vtc->vpi, VPI_PROTOCOL_OPCODE_ECHO, vtc->data, vtc->size) < 0) { return ucli_error(uc, "vpi_ioctl() failed."); } ucli_printf(uc, "waiting for response.\n"); memset(vtc->data, 0, sizeof(vtc->data)); if(vpi_recv__(uc, vtc) > 0) { ucli_printf(uc, "recv(%{vpi}):\n%{data}", vtc->vpi, vtc->data, vtc->size); return UCLI_STATUS_OK; } else { return UCLI_STATUS_E_ERROR; } }
static int ucli_vargparse_type__(ucli_context_t* uc, char c, char* type, const char* arg, aim_va_list_t* vargs) { int rv; aim_datatype_t* dt; if(arg == NULL) { return UCLI_STATUS_E_ARG; } if(type && type[0] == '%') { /* Immediate string specified. The argument must be that string. */ if(type[1] == 0) { /* No string */ return UCLI_STATUS_E_INTERNAL; } if(!UCLI_STRCMP(type+1, arg)) { return UCLI_STATUS_OK; } ucli_error(uc, "expected '%s', not '%s'", type+1, arg); return UCLI_STATUS_E_ARG; } dt = aim_datatype_find(c, type); if(dt == NULL) { /* Unrecognized type */ ucli_error(uc, "<bug: no handler for type '%c:%s'>", (c) ? c : '.', (type) ? type : "[NULL]"); AIM_LOG_ERROR("bug: no handler for type '%c:%s'", (c) ? c : '.', (type) ? type : "[NULL]"); return UCLI_STATUS_E_INTERNAL; } { aim_datatype_context_t dtc; dtc.dt = dt; dtc.epvs = &uc->pvs; rv = dt->from_str(&dtc, arg, vargs); } if( (rv < 0) && dt->desc) { ucli_e_arg(uc, arg, dt->desc); } return rv; }
static ucli_status_t ppe_ucli_utm__chm__(ucli_context_t* uc) { ppe_header_t header; int bool; UCLI_COMMAND_INFO(uc, "chm", 2, "Check the header mask."); UCLI_ARGPARSE_OR_RETURN(uc, "{ppe_header}{bool}", &header, &bool); if(bool && !(ppec->ppep.header_mask & (1 << header))) { return ucli_error(uc, "header bit %{ppe_header} is 0.", header); } if(!bool && (ppec->ppep.header_mask & (1 << header))) { return ucli_error(uc, "header bit %{ppe_header} is 1.", header); } return UCLI_STATUS_OK; }
ucli_status_t vt_ucli_module__send__(ucli_context_t* uc) { UCLI_COMMAND_INFO(uc, "send", 2, "$summary#Send a single packet on the given VPI." "$args#<vpi_spec> <packet_data>"); UCLI_ARGPARSE_OR_RETURN(uc, "{vpi}{idata}", &vtc->vpi, vtc->data, &vtc->size); if(vpi_send(vtc->vpi, vtc->data, vtc->size) < 0) { return ucli_error(uc, "vpi_send() failed."); } return UCLI_STATUS_OK; }
ucli_status_t vt_ucli_module__bridge__(ucli_context_t* uc) { vpi_t v1, v2; vpi_bridge_t vbridge; UCLI_COMMAND_INFO(uc, "bridge", 2, "$summary#Forward all packets between two VPI interfaces." "$args#<vpi_spec_1> <vpi_spec_2>"); UCLI_ARGPARSE_OR_RETURN(uc, "{vpi}{vpi}", &v1, &v2); vbridge = vpi_bridge_create(v1, v2); if(vbridge == NULL) { return ucli_error(uc, "vpi_bridge_create(%{vpi},%{vpi}) failed.", v1, v2); } if(vpi_bridge_start(vbridge) < 0) { return ucli_error(uc, "vpi_bridge_start() failed."); } vtc->bridges++; ucli_printf(uc, "bridging %s <-> %s\n", vpi_name_get(v1), vpi_name_get(v2)); return UCLI_STATUS_OK; }
static inline int field_required__(ucli_context_t* uc, ppe_field_t f) { AIM_VAR_PCAST_SAFE(ppe_utm_ctrl_t*, ppec, uc, uc->cookie); int e = ppe_field_exists(&ppec->ppep, f); if(e == 1) { return 0; } else if(e == 0) { return ucli_error(uc, "field %{ppe_field} does not exist in the packet.", f); } else { return ucli_e_internal(uc, "ppe_field_exists() failed internally."); } }
static ucli_status_t ppe_ucli_utm__checkf__(ucli_context_t* uc) { ppe_header_t cheader; ppe_header_t pheader; UCLI_COMMAND_INFO(uc, "checkf", 1, "Check the packet format."); UCLI_ARGPARSE_OR_RETURN(uc, "{ppe_header}", &cheader); ppe_packet_format_get(&ppec->ppep, &pheader); if(pheader != cheader) { return ucli_error(uc, "packet format is currently %{ppe_header}.", pheader); } return UCLI_STATUS_OK; }
ucli_status_t vt_ucli_module__sendrecv__(ucli_context_t* uc) { UCLI_COMMAND_INFO(uc, "sendrecv", 2, "$summary#Send a single packet on the given VPI and wait for a response." "$args#<vpi_spec> <packet_data>"); vtc->size = sizeof(vtc->data); UCLI_ARGPARSE_OR_RETURN(uc, "{vpi}{idata}", &vtc->vpi, vtc->data, &vtc->size); if(vpi_send(vtc->vpi, vtc->data, vtc->size) < 0) { return ucli_error(uc, "vpi_send() failed."); } if(vpi_recv__(uc, vtc) > 0) { ucli_printf(uc, "recv(%{vpi}):\n%{data}", vtc->vpi, vtc->data, vtc->size); return UCLI_STATUS_OK; } else { return UCLI_STATUS_E_ERROR; } }
ucli_status_t vt_ucli_module__spam__(ucli_context_t* uc) { aim_ratelimiter_t counter_rl; aim_ratelimiter_t send_rl; int count = 0; int last = 0; int pps = -1; UCLI_COMMAND_INFO(uc, "spam", 3, "$summary#Spam packet data on the given VPI." "$args#<vpi_spec> <packet_data> <pps>"); UCLI_ARGPARSE_OR_RETURN(uc, "{vpi}{idata}i", &vtc->vpi, vtc->data, &vtc->size, &pps); aim_ratelimiter_init(&counter_rl, 1000000, 0, NULL); aim_ratelimiter_init(&send_rl, 1000000/pps, 0, NULL); for(;;) { uint64_t now = os_time_monotonic(); if(aim_ratelimiter_limit(&counter_rl, now) == 0) { ucli_printf(uc, "Sent %d packets - %d pps\n", count, (count - last)); last = count; } if(aim_ratelimiter_limit(&send_rl, now) == 0) { if(vpi_send(vtc->vpi, vtc->data, vtc->size) < 0) { return ucli_error(uc, "vpi_send() failed."); } count++; } else { os_sleep_usecs(1); } } return UCLI_STATUS_OK; }
static ucli_status_t ppe_ucli_utm__missing__(ucli_context_t* uc) { ppe_field_t f; int rv; UCLI_COMMAND_INFO(uc, "missing", 1, "Check that a field is missing in the packet."); UCLI_ARGPARSE_OR_RETURN(uc, "{ppe_field}", &f); rv = ppe_field_exists(&ppec->ppep, f); if(rv == 0) { return UCLI_STATUS_OK; } else if(rv == 1) { return ucli_error(uc, "field %{ppe_field} exists in the packet.", f); } else { return ucli_e_internal(uc, "ppe_field_exists()"); } }
static ucli_status_t ppe_ucli_utm__dfk__(ucli_context_t* uc) { ppe_dfk_t dfk; ppe_field_t fields[4]; uint8_t* verify_data; unsigned int verify_data_size; int rv = UCLI_STATUS_OK; unsigned int i; UCLI_COMMAND_INFO(uc, "dfk", AIM_ARRAYSIZE(fields)+1, "Generate and verify a dynamic field key."); UCLI_ARGPARSE_OR_RETURN(uc, "{ppe_field}{ppe_field}{ppe_field}{ppe_field}{data}", fields+0, fields+1, fields+2, fields+3, &verify_data, &verify_data_size); ppe_dfk_init(&dfk, fields, AIM_ARRAYSIZE(fields)); i = ppe_packet_dfk(&ppec->ppep, &dfk); if(i != verify_data_size) { rv = ucli_error(uc, "dfk size is %d, verify data size is %d", i, verify_data_size); goto dfk_error; } for(i = 0; i < AIM_ARRAYSIZE(fields); i++) { const ppe_field_info_t* fi = ppe_field_info_get(fields[i]); int exists = ppe_field_exists(&ppec->ppep, fi->field); if(exists && ( (dfk.mask & (1<<i)) == 0)) { /* Should be in the field key but isn't.*/ rv = ucli_error(uc, "%{ppe_field} exists in packet but not in field key.", fi->field); goto dfk_error; } if(!(exists) && (dfk.mask & (1<<i))) { /* Should not be in the field key but is. */ rv = ucli_error(uc, "%{ppe_field} is in the key but not the packet.", fi->field); goto dfk_error; } } for(i = 0; i < verify_data_size; i++) { if(verify_data[i] != dfk.data[i]) { rv = ucli_error(uc, "key data mismatch at byte %d.\nkey=%{data}, verify=%{data}", i, dfk.data, verify_data_size, verify_data, verify_data_size); goto dfk_error; } } for(i = 0; i < AIM_ARRAYSIZE(fields); i++) { if(dfk.mask & (1<<i)) { const ppe_field_info_t* fi = ppe_field_info_get(fields[i]); if(fi->size_bits <= 32) { uint32_t pdata; uint32_t kdata; ppe_field_get(&ppec->ppep, fi->field, &pdata); ppe_dfk_field_get(&dfk, fi->field, &kdata); if(pdata != kdata) { rv = ucli_error(uc, "field_get mismatch: p=0x%x, k=0x%x"); goto dfk_error; } } else { unsigned int i; uint8_t pdata[128]; uint8_t kdata[128]; ppe_wide_field_get(&ppec->ppep, fi->field, pdata); ppe_dfk_wide_field_get(&dfk, fi->field, kdata); for(i = 0; i < fi->size_bits/8; i++) { if(pdata[i] != kdata[i]) { rv = ucli_error(uc, "wide_field_get mismatch @ %d: p=0x%x k=0x%x", i, pdata[i], kdata[i]); goto dfk_error; } } } } } aim_free(verify_data); ppe_dfk_destroy(&dfk); return UCLI_STATUS_OK; dfk_error: ucli_printf(uc, "key: "); ppe_dfk_show(&dfk, &uc->pvs); ppe_dfk_destroy(&dfk); aim_free(verify_data); ucli_printf(uc, "\n"); return rv; }
static ucli_status_t fme_ucli_utm__match__(ucli_context_t* uc) { int rv; int i; uint32_t keymask; uint8_t* value; int value_size; int _now; fme_timeval_t now; unsigned int size; fme_entry_t* fe = NULL; fme_key_t key; UCLI_COMMAND_INFO(uc, "match", 4, "Run the key and data."); UCLI_ARGPARSE_OR_RETURN(uc, "i{data}ii", &keymask, &value, &value_size, &size, &_now); now = _now; FME_MEMSET(&key, 0, sizeof(key)); key.keymask = keymask; FME_MEMCPY(key.values, value, value_size); key.size = value_size; FME_MEMSET(key.masks, 0, sizeof(key.masks)); aim_free(value); rv = fme_match(fmec->fme, &key, now, size, NULL, NULL, &fe); if(rv == 1) { if(fmec->expects[fe->prio] == 0) { /* Unexpected match */ ucli_error(uc, "unexpected match: "); fme_entry_dump(fe, &uc->pvs); goto __match__error; } /* match is expected -- check counter values */ if(fe->counters.matches != 1) { ucli_error(uc, "match counter was not incremented."); goto __match__error; } if(fe->counters.bytes != size) { ucli_error(uc, "byte counter is incorrect."); goto __match__error; } if(fe->timestamp != now) { ucli_error(uc, "timestamp was not updated."); goto __match__error; } /* all good */ } else if(rv == 0) { /* Make sure we have to entries expected to match */ for(i = 0; i < FME_CONFIG_UTM_ENTRIES; i++) { if(fmec->expects[i]) { ucli_error(uc, "expected match was not received: "); fme_entry_dump(fmec->entries[i], &uc->pvs); goto __match__error; } } /* all good */ } else { ucli_e_internal(uc, "fme_match() returned %d", rv); goto __match__error; } /* all good - reset */ fme_destroy_all(fmec->fme); FME_MEMSET(fmec, 0, sizeof(*fmec)); fme_create(&fmec->fme, "fme_utm", FME_CONFIG_UTM_ENTRIES); return UCLI_STATUS_OK; __match__error: ucli_error(uc, "fme: "); fme_dump(fmec->fme, &uc->pvs); return UCLI_STATUS_E_ERROR; }
static ucli_status_t ppe_ucli_utm__rwall__(ucli_context_t* uc) { ppe_packet_t ppep; ppe_header_t header; ppe_field_t f; int rv = UCLI_STATUS_OK; UCLI_COMMAND_INFO(uc, "rwall", 0, "Read and write all packet fields in all headers."); ppe_packet_init(&ppep, NULL, 0); /** * Allocate and assign a header pointer for every header type. * All bits will be initialized to 1. */ for(header = 0; header < PPE_HEADER_COUNT; header++) { uint8_t* hp = aim_zmalloc(1000); PPE_MEMSET(hp, 0xFF, 1000); ppe_header_set(&ppep, header, hp); } /** * Check that every field reads back as all 1's, with the correct width */ for(f = 0; f < PPE_FIELD_COUNT; f++) { const ppe_field_info_t* fi = ppe_field_info_get(f); if(fi->size_bits == 0) { continue; } if(fi->size_bits <= 32) { uint32_t v; ppe_field_get(&ppep, f, &v); if(fi->size_bits == 32) { if(v != 0xFFFFFFFF) { rv = ucli_error(uc, "first read: field %{ppe_field} is 0x%x, should be 0x%x", f, v, -1); } } else { if(v != ( (1U << fi->size_bits) - 1)) { rv = ucli_error(uc, "first read: field %{ppe_field} is 0x%x, should be 0x%x (%d bits)", f, v, (1<<fi->size_bits) - 1, fi->size_bits); } } /** clear field and re-read */ ppe_field_set(&ppep, f, 0); ppe_field_get(&ppep, f, &v); if(v != 0) { rv = ucli_error(uc, "second read: field %{ppe_field} is 0x%x when it should be 0.", f, v); } } else { uint8_t vb[64]; int bytes = ppe_wide_field_get(&ppep, f, vb); int i; for(i = 0; i < bytes; i++) { if(vb[i] != 0xFF) { rv = ucli_error(uc, "first read: field %{ppe_field}[%d] is 0x%.2x, should be 0x%.2x", f, i, vb[i], 0xFF); } } PPE_MEMSET(vb, 0, sizeof(vb)); /** clear field and re-read */ ppe_wide_field_set(&ppep, f, vb); PPE_MEMSET(vb, 0xFF, sizeof(vb)); ppe_wide_field_get(&ppep, f, vb); for(i = 0; i < bytes; i++) { if(vb[i] != 0) { rv = ucli_error(uc, "second read: field %{ppe_field}[%d] is 0x%.2x, should be 0.", f, i, vb[i]); } } } /** continue reading other fields, making sure the field we just cleared * does not change the value of fields we have not yet visited. */ } for(header = 0; header < PPE_HEADER_COUNT; header++) { aim_free(ppe_header_get(&ppep, header)); } return rv; }
int ucli_e_arg(ucli_context_t* uc, const char* arg, const char* desc) { ucli_error(uc, "argument '%s' is not a valid %s", arg, desc); return UCLI_STATUS_E_ARG; }