IETF 105 Hackathon
From Yuma123 Wiki
Plan
From https://trac.ietf.org/trac/ietf/meeting/wiki/105hackathon :
Transactional network test framework for flow capable bridge nodes ( OpenFlow, NETCONF )
* Champion(s)
* Vladimir Vassilev <vladimir at transpacket.com>
* Project(s)
* Drafts
* A YANG Data Model for Network Bridge Management
* A YANG Data Model for Network Interconnect Tester Management
* Node side (netconfd)
* traffic-generator and traffic-analyzer modules for Linux
* flow capable network bridge module OpenFlow->NETCONF convertor
* Controller side (OpenDaylight)
* Plugin for flow capable nodes with YANG/NETCONF interface
* Application side (python-tntapi, python-litenc, yangcli)
* RFC2544 implementation
* Environment (mininet)
* Topology instantiation script
* References
* https://tools.ietf.org/html/draft-vassilev-netmod-network-bridge
* https://tools.ietf.org/html/draft-vassilev-bmwg-network-interconnect-tester
* https://github.com/vlvassilev/yuma123/example-modules
Progress
- SIL module implementing ietf-traffic-generator.yang for netconfd
YANG tree:
| | +--:(multi-stream)
| | +--rw streams
| | +--rw stream* [id]
| | +--rw id uint32
| | +--rw frame-size uint32
| | +--rw (frame-data-type)?
| | | +--:(raw-frame-data)
| | | +--rw frame-data? string
| | +--rw interframe-gap uint32
| | +--rw interburst-gap? uint32
| | +--rw frames-per-burst? uint32
| | +--rw frames-per-stream uint32
| | +--rw interstream-gap uint32
| | +--rw src-mac-address? yang:mac-address {ethernet}?
| | +--rw dst-mac-address? yang:mac-address {ethernet}?
| | +--rw ether-type? uint16 {ethernet}?
| | +--rw (encapsulation)? {ethernet}?
| | +--:(vlan)
| | +--rw vlan {ethernet-vlan}?
| | +--rw id uint16
| | +--rw tpid? uint16
| | +--rw pcp? uint8
| | +--rw cfi? uint8
| +--rw total-frames? uint64
C implementation:
static void traffic_generator_delete(val_value_t* traffic_generator_val)
{
char cmd_buf[512];
val_value_t* name_val;
printf("traffic_generator_delete:\n");
val_dump_value(traffic_generator_val,NCX_DEF_INDENT);
name_val = val_find_child(traffic_generator_val->parent,"ietf-interfaces","name");
assert(name_val);
sprintf(cmd_buf, "pkill -f 'traffic-generator %s blah'", VAL_STRING(name_val));
system(cmd_buf);
}
static void traffic_generator_create(val_value_t* traffic_generator_val)
{
char cmd_buf[512];
val_value_t* name_val;
printf("traffic_generator_create:\n");
val_dump_value(traffic_generator_val,NCX_DEF_INDENT);
name_val = val_find_child(traffic_generator_val->parent,"ietf-interfaces","name");
assert(name_val);
sprintf(cmd_buf, "traffic-generator %s blah &", VAL_STRING(name_val));
system(cmd_buf);
}
/* 2 step (delete/add) interface configuration */
/* 1. deactivation loop - deletes all deleted or modified interface/traffic-generator -s */
if(interfaces_cur_val!=NULL) {
for (interface_cur_val = val_get_first_child(interfaces_cur_val);
interface_cur_val != NULL;
interface_cur_val = val_get_next_child(interface_cur_val)) {
traffic_generator_cur_val = val_find_child(interface_cur_val, TG_MOD, "traffic-generator");
if(traffic_generator_cur_val==NULL) {
continue;
}
traffic_generator_new_val = val123_find_match(config_new_val, traffic_generator_cur_val);
if(traffic_generator_new_val==NULL || 0!=val_compare_ex(traffic_generator_cur_val,traffic_generator_new_val,TRUE)) {
traffic_generator_delete(traffic_generator_cur_val);
}
}
}
/* 2. activation loop - adds all new or modified interface/traffic-generator -s */
if(interfaces_new_val!=NULL) {
for (interface_new_val = val_get_first_child(interfaces_new_val);
interface_new_val != NULL;
interface_new_val = val_get_next_child(interface_new_val)) {
traffic_generator_new_val = val_find_child(interface_new_val, TG_MOD, "traffic-generator");
if(traffic_generator_new_val==NULL) {
continue;
}
traffic_generator_cur_val = val123_find_match(config_cur_val, traffic_generator_new_val);
if(traffic_generator_cur_val==NULL || 0!=val_compare_ex(traffic_generator_new_val,traffic_generator_cur_val,TRUE)) {
traffic_generator_create(traffic_generator_new_val);
}
}
}
...
#include <stdint.h>
typedef struct burst_t_ {
uint32_t frame_length;
uint8_t* raw_frame_data;
uint32_t interframe_gap;
uint32_t frames_per_burst;
uint32_t interburst_gap;
} burst_t;
typedef struct stream_t_ {
unsigned int bursts_per_stream;
unsigned int burst_index;
uint32_t interstream_gap;
burst_t* bursts;
} stream_t;
typedef struct traffic_generator_t_ {
uint64_t total_frames;
uint64_t total_frame_index;
uint64_t sec;
uint32_t nsec;
float ns_per_octet;
stream_t* streams;
unsigned int streams_num;
unsigned int stream_index;
unsigned int burst_index;
unsigned int frame_index;
} traffic_generator_t;
traffic_generator_t* traffic_generator_init(const char* config_str);
int traffic_generator_get_frame(traffic_generator_t* tg, uint32_t* frame_length, uint8_t** frame, uint64_t* tx_time_sec, uint32_t* tx_time_nsec);
...
while(1) {
ret = traffic_generator_get_frame(tg, &frame_len, &frame_buf, &tx_time_sec, &tx_time_nsec);
if(ret!=0) {
break;
}
clock_gettime( CLOCK_MONOTONIC, &now);
rel.tv_sec = tx_time_sec; /* seconds */
rel.tv_nsec = tx_time_nsec; /* nanoseconds */
timespec_add(&rel, &epoch, &abs);
timespec_sub(&now, &abs, &req);
ret=nanosleep(&req,&rem);
//assert(ret==0);
ret = raw_socket_send(&raw_socket, frame_buf, frame_len);
assert(ret==0);
if(now.tv_sec>print_sec) {
print_sec=now.tv_sec;
printf("%llu\n",frm);
}
frm++;
}