Commit 85b04df2 authored by Barath Raghavan's avatar Barath Raghavan Committed by GitHub
Browse files

Checkpoint of C++ development branch. (#197)

* bessctl: fix tc bugs (#172)

This patch removes an unecessary error from AttachTask and fixes show tc

* No warning when daemon starts

* bessctl/scripts: fix queue

* fix divide by zero bug causing bpf.bess to crash

* Check in commit re: rate limiter inaccuracy.

* modules/measure: add median, 99% latency to output

* scripts: fix vxlan.bess

* Updates time accounting after throttling.

* bessctl: Do not run most commands when daemon is not connected

* Make name and arg arguments optional

* Allow burst=0 to disable packet generation

* Print request/response msgs only in debug mode (#176)

* Changes task attachment is bessctl.

* Fix incorrect handling of vdev argument

* Implicitly convert to name when use Port/Module as parameter

* module/set_metadata: Accept both value_hex and value_int

* scripts: minor fix

* scripts: Fixed parameters of SetMetadata

* Minor fix

* bessctl: No protobuf debug message when v=1 is not given

* Add sanity check script that execs a bunch of bess configs and makes sure they
don't crash.

* bessctl: fix show tc (#182)

* traffic_class: add general traversal method

* bessctl: correctly pair workers/tcs in show tc

* traffic_class: override Traverse() for derived tcs

clang++-3.8 build fails otherwise.

* traffic_class: add Size() tests

* traffic_class: free leaf tc tasks when resetting (#183)

* bessctl: report cycles/pkt and pkts/sched as ints

Floats gave the false impression of extra precision.

* drivers/pmd: clean up port selection

* bessctl: don't crash when tab completing w/o bessd

* drivers/pmd: comment dpdk device helpers

* Add sanity check to travis. (#187)

* Revert "Add sanity check to travis." (#188)

* module: Fix a bug in IPLookup (#190)
parent d425b5b2
......@@ -110,8 +110,8 @@ def connect_bess():
sock.close()
s.connect()
except socket.error as e:
print >> sys.stderr, e
pass
return s
......
......@@ -66,6 +66,8 @@ class CLI(object):
def err(self, msg):
self.fout.write('*** Error: %s\n' % msg)
if not self.interactive:
sys.exit(2)
# If not a variable, simply return None
# Otherwise, return (var_type, desc, candidates):
......
......@@ -29,6 +29,23 @@ class ConfError(Exception):
pass
@staticmethod
def _choose_arg(arg, kwargs):
if kwargs:
if arg:
raise TypeError('You cannot specify both arg and keyword args')
for key in kwargs:
if isinstance(kwargs[key], (Module, Port)):
kwargs[key] = kwargs[key].name
return kwargs
if isinstance(arg, (Module, Port)):
return arg.name
else:
return arg
def __bess_env__(key, default=None):
try:
return os.environ[key]
......@@ -134,28 +151,43 @@ def get_var_attrs(cli, var_token, partial_word):
elif var_token == 'WORKER_ID...':
var_type = 'wid+'
var_desc = 'one or more worker IDs'
var_candidates = [str(m.wid)
for m in cli.bess.list_workers().workers_status]
try:
var_candidates = [str(m.wid) for m in \
cli.bess.list_workers().workers_status]
except:
pass
elif var_token == 'DRIVER':
var_type = 'name'
var_desc = 'name of a port driver'
var_candidates = cli.bess.list_drivers().driver_names
try:
var_candidates = cli.bess.list_drivers().driver_names
except:
pass
elif var_token == 'DRIVER...':
var_type = 'name'
var_desc = 'one or more port driver names'
var_candidates = cli.bess.list_drivers().driver_names
try:
var_candidates = cli.bess.list_drivers().driver_names
except:
pass
elif var_token == 'MCLASS':
var_type = 'name'
var_desc = 'name of a module class'
var_candidates = cli.bess.list_mclasses().names
try:
var_candidates = cli.bess.list_mclasses().names
except:
pass
elif var_token == 'MCLASS...':
var_type = 'name+'
var_desc = 'one or more module class names'
var_candidates = cli.bess.list_mclasses().names
try:
var_candidates = cli.bess.list_mclasses().names
except:
pass
elif var_token == '[NEW_MODULE]':
var_type = 'name'
......@@ -164,12 +196,20 @@ def get_var_attrs(cli, var_token, partial_word):
elif var_token == 'MODULE':
var_type = 'name'
var_desc = 'name of an existing module instance'
var_candidates = [m.name for m in cli.bess.list_modules().modules]
try:
var_candidates = [m.name for m in \
cli.bess.list_modules().modules]
except:
pass
elif var_token == 'MODULE...':
var_type = 'name+'
var_desc = 'one or more module names'
var_candidates = [m.name for m in cli.bess.list_modules().modules]
try:
var_candidates = [m.name for m in \
cli.bess.list_modules().modules]
except:
pass
elif var_token == 'MODULE_CMD':
var_type = 'name'
......@@ -182,17 +222,27 @@ def get_var_attrs(cli, var_token, partial_word):
elif var_token == 'PORT':
var_type = 'name'
var_desc = 'name of a port'
var_candidates = [p.name for p in cli.bess.list_ports().ports]
try:
var_candidates = [p.name for p in cli.bess.list_ports().ports]
except:
pass
elif var_token == 'PORT...':
var_type = 'name+'
var_desc = 'one or more port names'
var_candidates = [p.name for p in cli.bess.list_ports().ports]
try:
var_candidates = [p.name for p in cli.bess.list_ports().ports]
except:
pass
elif var_token == 'TC...':
var_type = 'name+'
var_desc = 'one or more traffic class names'
var_candidates = [getattr(c, 'class').name for c in cli.bess.list_tcs().classes_status]
try:
var_candidates = [getattr(c, 'class').name \
for c in cli.bess.list_tcs().classes_status]
except:
pass
elif var_token == 'CONF':
var_type = 'confname'
......@@ -513,6 +563,10 @@ def daemon_start(cli, opts):
_do_start(cli, opts)
def is_bess_connected(cli):
return cli.bess.is_connected()
def is_pipeline_empty(cli):
workers = cli.bess.list_workers().workers_status
modules = cli.bess.list_modules().modules
......@@ -530,6 +584,10 @@ def _do_reset(cli):
@cmd('daemon reset', 'Remove all ports and modules in the pipeline')
def daemon_reset(cli):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
if is_pipeline_empty(cli):
_do_reset(cli)
else:
......@@ -545,6 +603,10 @@ def _do_stop(cli):
@cmd('daemon stop', 'Stop BESS daemon')
def daemon_stop(cli):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
if is_pipeline_empty(cli):
_do_stop(cli)
else:
......@@ -581,7 +643,7 @@ def _do_run_file(cli, conf_file):
raise cli.InternalError('Invalid driver name: %s' % name)
new_globals[name] = type(str(name), (Port,),
{'bess': cli.bess})
{'bess': cli.bess, 'choose_arg': _choose_arg})
# Add BESS module classes
for name in class_names:
......@@ -589,7 +651,7 @@ def _do_run_file(cli, conf_file):
raise cli.InternalError('Invalid module class name: %s' % name)
new_globals[name] = type(str(name), (Module,),
{'bess': cli.bess})
{'bess': cli.bess, 'choose_arg': _choose_arg})
code = compile(xformed, conf_file, 'exec')
......@@ -646,6 +708,10 @@ def _run_file(cli, conf_file, env_map):
@cmd('run CONF [ENV_VARS...]', 'Run a *.bess configuration in "conf/"')
def run_conf(cli, conf, env_map):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
target_dir = '%s/conf' % cli.this_dir
basename = os.path.expanduser('%s.%s' % (conf, CONF_EXT))
conf_file = os.path.join(target_dir, basename)
......@@ -654,11 +720,19 @@ def run_conf(cli, conf, env_map):
@cmd('run file CONF_FILE [ENV_VARS...]', 'Run a configuration file')
def run_file(cli, conf_file, env_map):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
_run_file(cli, os.path.expanduser(conf_file), env_map)
@cmd('add port DRIVER [NEW_PORT] [PORT_ARGS...]', 'Add a new port')
def add_port(cli, driver, port, args):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
ret = cli.bess.create_port(driver, port, args)
if port is None:
......@@ -667,6 +741,10 @@ def add_port(cli, driver, port, args):
@cmd('add module MCLASS [NEW_MODULE] [MODULE_ARGS...]', 'Add a new module')
def add_module(cli, mclass, module, args):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
cli.bess.pause_all()
try:
ret = cli.bess.create_module(mclass, module, args)
......@@ -680,6 +758,10 @@ def add_module(cli, mclass, module, args):
@cmd('add connection MODULE MODULE [OGATE] [IGATE]',
'Add a connection between two modules')
def add_connection(cli, m1, m2, ogate, igate):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
if ogate is None:
ogate = 0
......@@ -696,6 +778,10 @@ def add_connection(cli, m1, m2, ogate, igate):
@cmd('command module MODULE MODULE_CMD ARG_TYPE [CMD_ARGS...]',
'Send a command to a module')
def command_module(cli, module, cmd, arg_type, args):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
cli.bess.pause_all()
try:
ret = cli.bess.run_module_command(module, cmd, arg_type, args)
......@@ -706,11 +792,19 @@ def command_module(cli, module, cmd, arg_type, args):
@cmd('delete port PORT', 'Delete a port')
def delete_port(cli, port):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
cli.bess.destroy_port(port)
@cmd('delete module MODULE', 'Delete a module')
def delete_module(cli, module):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
cli.bess.pause_all()
try:
cli.bess.destroy_module(module)
......@@ -721,6 +815,10 @@ def delete_module(cli, module):
@cmd('delete connection MODULE ogate [OGATE]',
'Delete a connection between two modules')
def delete_connection(cli, module, ogate):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
if ogate is None:
ogate = 0
......@@ -751,6 +849,10 @@ def _show_worker(cli, w):
@cmd('show worker', 'Show the status of all worker threads')
def show_worker_all(cli):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
workers = cli.bess.list_workers().workers_status
if len(workers) == 0:
......@@ -763,6 +865,10 @@ def show_worker_all(cli):
@cmd('show worker WORKER_ID...', 'Show the status of specified worker threads')
def show_worker_list(cli, worker_ids):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
workers = cli.bess.list_workers().workers_status
for wid in worker_ids:
......@@ -821,23 +927,33 @@ def _show_tc_list(cli, tcs):
cli.fout.write(' worker %d (%d classes)\n' % (wid, len(matched)))
for tc in matched:
c_ = getattr(tc, 'class')
cli.fout.write(' %-16s ' \
'parent %-10s priority %-3d tasks %-3d ' \
'parent %-10s %s %-3d tasks %-3d ' \
'%s\n' % \
(getattr(tc, 'class').name,
(c_.name,
tc.parent if tc.parent else 'none',
getattr(tc, 'class').priority_share,
'priority' if c_.HasField('priority') else 'share',
c_.priority if c_.HasField('priority') else c_.share,
tc.tasks,
_limit_to_str(getattr(tc, 'class').limit)))
_limit_to_str(c_.limit)))
@cmd('show tc', 'Show the list of traffic classes')
def show_tc_all(cli):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
_show_tc_list(cli, cli.bess.list_tcs().classes_status)
@cmd('show tc worker WORKER_ID...', 'Show the list of traffic classes')
def show_tc_workers(cli, wids):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
wids = sorted(list(set(wids)))
for wid in wids:
_show_tc_list(cli, cli.bess.list_tcs(wid).classes_status)
......@@ -845,6 +961,10 @@ def show_tc_workers(cli, wids):
@cmd('show status', 'Show the overall status')
def show_status(cli):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
workers = sorted(cli.bess.list_workers().workers_status,
key=lambda x: x.wid)
drivers = sorted(cli.bess.list_drivers().driver_names)
......@@ -949,12 +1069,20 @@ def _draw_pipeline(cli, field, last_stats=None):
@cmd('show pipeline', 'Show the current datapath pipeline')
def show_pipeline(cli):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
cli.fout.write(_draw_pipeline(cli, 'pkts'))
@cmd('show pipeline batch',
'Show the current datapath pipeline with batch counters')
def show_pipeline_batch(cli):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
cli.fout.write(_draw_pipeline(cli, 'cnt'))
......@@ -985,6 +1113,10 @@ def _show_port(cli, port):
@cmd('show port', 'Show the status of all ports')
def show_port_all(cli):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
ports = cli.bess.list_ports().ports
if len(ports) == 0:
......@@ -996,6 +1128,10 @@ def show_port_all(cli):
@cmd('show port PORT...', 'Show the status of spcified ports')
def show_port_list(cli, port_names):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
ports = cli.bess.list_ports().ports
port_names = list(set(port_names))
......@@ -1011,9 +1147,7 @@ def show_port_list(cli, port_names):
def _show_module(cli, module_name):
info = cli.bess.get_module_info(module_name)
cli.fout.write(' %s::%s' % (info.name, info.mclass))
cli.fout.write(' (%s)\n' % info.desc)
cli.fout.write(' %s::%s(%s)\n' % (info.name, info.mclass, info.desc))
if len(info.metadata) > 0:
cli.fout.write(' Per-packet metadata fields:\n')
......@@ -1066,6 +1200,10 @@ def _show_module(cli, module_name):
@cmd('show module', 'Show the status of all modules')
def show_module_all(cli):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
modules = cli.bess.list_modules().modules
if not modules:
......@@ -1077,6 +1215,10 @@ def show_module_all(cli):
@cmd('show module MODULE...', 'Show the status of specified modules')
def show_module_list(cli, module_names):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
for module_name in module_names:
_show_module(cli, module_name)
......@@ -1094,6 +1236,10 @@ def _show_mclass(cli, cls_name, detail):
@cmd('show mclass', 'Show all module classes')
def show_mclass_all(cli):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
mclasses = cli.bess.list_mclasses().names
for cls_name in mclasses:
_show_mclass(cli, cls_name, False)
......@@ -1101,6 +1247,10 @@ def show_mclass_all(cli):
@cmd('show mclass MCLASS...', 'Show the details of specified module classes')
def show_mclass_list(cli, cls_names):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
for cls_name in cls_names:
_show_mclass(cli, cls_name, True)
......@@ -1118,6 +1268,10 @@ def _show_driver(cli, drv_name, detail):
@cmd('show driver', 'Show all port drivers')
def show_driver_all(cli):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
drivers = cli.bess.list_drivers().driver_names
for drv_name in drivers:
......@@ -1126,6 +1280,10 @@ def show_driver_all(cli):
@cmd('show driver DRIVER...', 'Show the details of specified drivers')
def show_driver_list(cli, drv_names):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
for drv_name in drv_names:
_show_driver(cli, drv_name, True)
......@@ -1152,12 +1310,20 @@ def _monitor_pipeline(cli, field):
@cmd('monitor pipeline', 'Monitor packet counters in the datapath pipeline')
def monitor_pipeline(cli):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
_monitor_pipeline(cli, 'pkts')
@cmd('monitor pipeline batch',
'Monitor batch counters in the datapath pipeline')
def monitor_pipeline_batch(cli):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
_monitor_pipeline(cli, 'cnt')
......@@ -1255,11 +1421,19 @@ def _monitor_ports(cli, *ports):
@cmd('monitor port', 'Monitor the current traffic of all ports')
def monitor_port_all(cli):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
_monitor_ports(cli)
@cmd('monitor port PORT...', 'Monitor the current traffic of specified ports')
def monitor_port_all(cli, ports):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
_monitor_ports(cli, *ports)
......@@ -1302,7 +1476,7 @@ def _monitor_tcs(cli, *tcs):
else:
cpp = 0
cli.fout.write('%-20s%12.3f%12d%12.3f%12.3f%12.3f%12.3f\n' %
cli.fout.write('%-20s%12.3f%12d%12.3f%12.3f%12d%12d\n' %
(tc,
delta.cycles / 1e6,
delta.count,
......@@ -1353,11 +1527,19 @@ def _monitor_tcs(cli, *tcs):
@cmd('monitor tc', 'Monitor the statistics of all traffic classes')
def monitor_tc_all(cli):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
_monitor_tcs(cli)
@cmd('monitor tc TC...', 'Monitor the statistics of specified traffic classes')
def monitor_tc_all(cli, tcs):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
_monitor_tcs(cli, *tcs)
......@@ -1365,6 +1547,10 @@ def monitor_tc_all(cli, tcs):
@cmd('tcpdump MODULE [DIRECTION] [OGATE] [TCPDUMP_OPTS...]',
'Capture packets on a gate')
def tcpdump_module(cli, module_name, direction, gate, opts):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
if gate is None:
gate = 0
......@@ -1416,6 +1602,10 @@ def tcpdump_module(cli, module_name, direction, gate, opts):
@cmd('track ENABLE_DISABLE [MODULE] [DIRECTION] [GATE]',
'Count the packets and batches on a gate')
def track_module(cli, flag, module_name, direction, gate):
if not is_bess_connected(cli):
cli.err('BESS daemon is not connected')
return
if direction is None:
direction = 'out'
......
......@@ -4,13 +4,13 @@
em::ExactMatch(fields=[{'attr':'foo', 'size':1}, \
{'attr':'bar', 'size':2}])
Source() \
-> SetMetadata(attrs=[{'name': 'foo', 'size': 1, 'value': 0xcc}]) \
-> SetMetadata(attrs=[{'name': 'bar', 'size': 2, 'value': 0x1122}]) \
-> SetMetadata(attrs=[{'name': 'foo', 'size': 1, 'value_int': 0xcc}]) \
-> SetMetadata(attrs=[{'name': 'bar', 'size': 2, 'value_int': 0x1122}]) \
-> em
Source() \
-> SetMetadata(attrs=[{'name':'bar', 'size':2, 'value':0x3344},
{'name':'foo', 'size':1, 'value':0x42}]) \
-> SetMetadata(attrs=[{'name':'bar', 'size':2, 'value_int':0x3344},
{'name':'foo', 'size':1, 'value_int':0x42}]) \
-> em
em.set_default_gate(0)
......
......@@ -10,7 +10,7 @@ payload = 'Hello World'
test_packet = str(eth/ip/udp/payload)
Source() \
-> SetMetadata(attrs=[{'name': 'ether_type', 'size': 2, 'value': 0x9999}]) \
-> SetMetadata(attrs=[{'name': 'ether_type', 'size': 2, 'value_int': 0x9999}]) \
-> Rewrite(templates=[test_packet]) \
-> GenericEncap(fields=[ \
{'size': 6, 'value': 0x020000000001},
......
......@@ -20,6 +20,8 @@ while True:
diff_pkts = (last.packets - now.packets) / diff_ts
diff_bits = (last.bits - now.bits) / diff_ts
diff_total_latency_ns = (last.total_latency_ns - now.total_latency_ns) / diff_ts
diff_latency_50_ns = (last.latency_50_ns - now.latency_50_ns) / diff_ts
diff_latency_99_ns = (last.latency_99_ns - now.latency_99_ns) / diff_ts
last = now
if diff_pkts >= 1.0:
......@@ -27,8 +29,10 @@ while True:
else:
ns_per_packet = 0
print '%s: %.3f Mpps, %.3f Mbps, %.3f us' % \
print '%s: %.3f Mpps, %.3f Mbps, %.3f us, %.3f us, %.3f us' % \
(time.ctime(now.timestamp),
diff_pkts / 1e6,
diff_bits / 1e6,
ns_per_packet / 1e3)
ns_per_packet / 1e3,
last.latency_50_ns / 1e3,
now.latency_50_ns / 1e3)
......@@ -13,8 +13,13 @@ src::Source() \
-> VLANPush(tci=2) \
-> Sink()
bess.add_tc('fast', limit={'packets': 9000000})
bess.add_tc('slow', limit={'packets': 1000000})
bess.add_tc('rr', policy='round_robin', priority=0)
bess.attach_task(src.name, tc='fast')
bess.attach_task(queue.name, tc='slow')
bess.add_tc('fast', policy='rate_limit', resource='packet', limit={'packet': 9000000}, parent='rr')
bess.add_tc('fast_leaf', policy='leaf', parent='fast')
bess.add_tc('slow', policy='rate_limit', resource='packet', limit={'packet': 1000000}, parent='rr')
bess.add_tc('slow_leaf', policy='leaf', parent='slow')
bess.attach_task(src.name, tc='fast_leaf')
bess.attach_task(queue.name, tc='slow_leaf')
......@@ -53,14 +53,14 @@ PortInc(port=v_alice) -> bpf::BPF():1 -> VXLANDecap() -> PortOut(port=v_bob)
# Bob -> Alice
PortInc(port=v_bob) \
-> SetMetadata(attrs=
[{'name': 'tun_ip_src', 'size': 4, 'value': aton('10.0.10.1')},
{'name': 'tun_ip_dst', 'size': 4, 'value': aton('10.0.10.2')},
{'name': 'tun_id', 'size': 4, 'value': 999}]) \
[{'name': 'tun_ip_src', 'size': 4, 'value_hex': aton('10.0.10.1')},
{'name': 'tun_ip_dst', 'size': 4, 'value_hex': aton('10.0.10.2')},
{'name': 'tun_id', 'size': 4, 'value_int': 999}]) \
-> VXLANEncap(dstport=4789) \
-> IPEncap() \
-> SetMetadata(attrs=
[{'name': 'ether_src', 'size': 6, 'value': '\x02\x01\x02\x03\x04\x05'},
{'name': 'ether_dst', 'size': 6, 'value': '\x02\x0a\x0b\x0c\x0d\x0e'}]) \
[{'name': 'ether_src', 'size': 6, 'value_hex': '\x02\x01\x02\x03\x04\x05'},
{'name': 'ether_dst', 'size': 6, 'value_hex': '\x02\x0a\x0b\x0c\x0d\x0e'}]) \
-> EtherEncap() \
-> PortOut(port=v_alice)
......
......@@ -27,8 +27,8 @@ wm::WildcardMatch(fields=[{'offset':30, 'size':4},
{'attribute':'in_port', 'size':2}])
# locally emulate two input ports
Source() -> SetMetadata(attrs=[{'name': 'in_port', 'size': 2, 'value': 1}]) -> Rewrite(templates=pkts) -> wm
Source() -> SetMetadata(attrs=[{'name': 'in_port', 'size': 2, 'value': 2}]) -> Rewrite(templates=pkts) -> wm
Source() -> SetMetadata(attrs=[{'name': 'in_port', 'size': 2, 'value_int': 1}]) -> Rewrite(templates=pkts) -> wm
Source() -> SetMetadata(attrs=[{'name': 'in_port', 'size': 2, 'value_int': 2}]) -> Rewrite(templates=pkts) -> wm
wm:0 -> Sink()
wm:1 -> Sink()
......
......@@ -20,7 +20,8 @@ class Module(object):
else:
name = None
ret = self.bess.create_module(self.__class__.__name__, name, kwargs)
ret = self.bess.create_module(self.__class__.__name__, name,
self.choose_arg(None, kwargs))
self.name = ret.name
print 'Module %s created' % self
......
......@@ -7,7 +7,8 @@ class Port(object):
name = kwargs.pop('name', None)
ret = self.bess.create_port(self.driver, name, kwargs)
ret = self.bess.create_port(self.driver, name,
self.choose_arg(None, kwargs))
self.name = ret.name
......
......@@ -300,7 +300,7 @@ static Module* create_module(const std::string& name,
ctx.SetNonWorker();
*perr = m->InitWithGenericArg(arg);
if (perr->err() != 0) {
LOG(INFO) << perr->DebugString();
VLOG(1) << perr->DebugString();
ModuleBuilder::DestroyModule(m); // XXX: fix me
return nullptr;
}
......@@ -412,56 +412,80 @@ class BESSControlImpl final : public BESSControl::Service {
}
Status ListTcs(ServerContext*, const ListTcsRequest* request,
ListTcsResponse* response) override {
unsigned int wid_filter = MAX_WORKERS;
int wid_filter;
int i;
wid_filter = request->wid();
if (wid_filter >= MAX_WORKERS) {
if (wid_filter >= num_workers) {
return return_with_error(
response, EINVAL, "'wid' must be between 0 and %d", MAX_WORKERS - 1);
response, EINVAL, "'wid' must be between 0 and %d", num_workers - 1);
}
if (!is_worker_active(wid_filter)) {
return return_with_error(response, EINVAL, "worker:%d does not exist",
wid_filter);
if (wid_filter < 0) {
i = 0;
wid_filter = num_workers - 1;
} else {
i = wid_filter;
}
for (const auto& pair : TrafficClassBuilder::all_tcs()) {
bess::TrafficClass* c = pair.second;
struct traverse_arg {
ListTcsResponse* response;
int wid;
};
ListTcsResponse_TrafficClassStatus* status =
response->add_classes_status();
if (c->parent()) {
status->set_parent(c->parent()->name());
}
status->mutable_class_()->set_name(c->name());
status->mutable_class_()->set_blocked(c->blocked());
if (c->policy() >= 0 && c->policy() < bess::NUM_POLICIES) {
status->mutable_class_()->set_policy(
bess::TrafficPolicyName[c->policy()]);
} else {
status->mutable_class_()->set_policy("invalid");
for (; i <= wid_filter; i++) {
const bess::TrafficClass* root = workers[i]->scheduler()->root();
if (!root) {
return return_with_error(response, ENOENT, "worker:%d has no root tc",
i);
}
if (c->policy() == bess::POLICY_LEAF) {
status->set_tasks(
reinterpret_cast<bess::LeafTrafficClass*>(c)->tasks().size());
}
status->mutable_class_()->set_wid(wid_filter);
if (c->policy() == bess::POLICY_RATE_LIMIT) {
bess::RateLimitTrafficClass* rl =
reinterpret_cast<bess::RateLimitTrafficClass*>(c);
std::string resource = bess::ResourceName.at(rl->resource());
int64_t limit = rl->limit();
int64_t max_burst = rl->max_burst();
status->mutable_class_()->mutable_limit()->insert({resource, limit});
status->mutable_class_()->mutable_max_burst()->insert(
{resource, max_burst});
}
struct traverse_arg arg__ = {response, i};
root->Traverse(
[](const bess::TrafficClass* c, void* arg) {
struct traverse_arg* arg_ =
reinterpret_cast<struct traverse_arg*>(arg);
ListTcsResponse_TrafficClassStatus* status =
arg_->response->add_classes_status();
if (c->parent()) {
status->set_parent(c->parent()->name());
}
status->mutable_class_()->set_name(c->name());
status->mutable_class_()->set_blocked(c->blocked());
if (c->policy() >= 0 && c->policy() < bess::NUM_POLICIES) {
status->mutable_class_()->set_policy(
bess::TrafficPolicyName[c->policy()]);
} else {
status->mutable_class_()->set_policy("invalid");
}
if (c->policy() == bess::POLICY_LEAF) {
status->set_tasks(
reinterpret_cast<const bess::LeafTrafficClass*>(c)
->tasks()
.size());
}
status->mutable_class_()->set_wid(arg_->wid);
if (c->policy() == bess::POLICY_RATE_LIMIT) {
const bess::RateLimitTrafficClass* rl =
reinterpret_cast<const bess::RateLimitTrafficClass*>(c);
std::string resource = bess::ResourceName.at(rl->resource());
int64_t limit = rl->limit();
int64_t max_burst = rl->max_burst();
status->mutable_class_()->mutable_limit()->insert(
{resource, limit});
status->mutable_class_()->mutable_max_burst()->insert(
{resource, max_burst});
}
},
static_cast<void*>(&arg__));
}
return Status::OK;
......@@ -700,8 +724,8 @@ class BESSControlImpl final : public BESSControl::Service {
const char* driver_name;
::Port* port = nullptr;
LOG(INFO) << "CreatePortRequest from client:" << std::endl
<< request->DebugString();
VLOG(1) << "CreatePortRequest from client:" << std::endl
<< request->DebugString();
if (request->driver().length() == 0)
return return_with_error(response, EINVAL, "Missing 'driver' field");
......@@ -807,8 +831,8 @@ class BESSControlImpl final : public BESSControl::Service {
return return_with_error(response, EBUSY, "There is a running worker");
}
LOG(INFO) << "CreateModuleRequest from client:" << std::endl
<< request->DebugString();
VLOG(1) << "CreateModuleRequest from client:" << std::endl
<< request->DebugString();
if (!request->mclass().length()) {
return return_with_error(response, EINVAL, "Missing 'mclass' field");
......@@ -1019,13 +1043,6 @@ class BESSControlImpl final : public BESSControl::Service {
}
} else if (request->identifier_case() ==
bess::pb::AttachTaskRequest::kWid) {
if (t->c()) {
return return_with_error(response, EBUSY,
"Task %s:%hu is already "
"attached to a TC",
request->name().c_str(), tid);
}
int wid = request->wid(); /* TODO: worker_id_t */
if (wid >= MAX_WORKERS) {
return return_with_error(response, EINVAL,
......@@ -1044,7 +1061,7 @@ class BESSControlImpl final : public BESSControl::Service {
return return_with_error(response, ENOENT,
"Worker %d has no default leaf tc", wid);
}
tc->AddTask(t);
t->Attach(tc);
} else {
return return_with_error(response, EINVAL, "Both tc and wid are not set");
}
......
......@@ -110,84 +110,106 @@ void PMDPort::InitDriver() {
}
}
static pb_error_t find_dpdk_port(dpdk_port_t port_id, const std::string &pci,
const std::string &vdev,
dpdk_port_t *ret_port_id,
bool *ret_hot_plugged) {
// Find a port attached to DPDK by its integral id.
// returns 0 and sets *ret_port_id to "port_id" if the port is valid and
// available.
// returns > 0 on error.
static pb_error_t find_dpdk_port_by_id(dpdk_port_t port_id,
dpdk_port_t *ret_port_id) {
if (port_id >= RTE_MAX_ETHPORTS) {
return pb_error(EINVAL, "Invalid port id %d", port_id);
}
if (!rte_eth_devices[port_id].attached) {
return pb_error(ENODEV, "Port id %d is not available", port_id);
}
*ret_port_id = port_id;
return pb_errno(0);
}
// Find a port attached to DPDK by its PCI address.
// returns 0 and sets *ret_port_id to the port_id of the port at PCI address
// "pci" if it is valid and available. *ret_hot_plugged is set to true if the
// device was attached to DPDK as a result of calling this function.
// returns > 0 on error.
static pb_error_t find_dpdk_port_by_pci_addr(const std::string &pci,
dpdk_port_t *ret_port_id,
bool *ret_hot_plugged) {
dpdk_port_t port_id = DPDK_PORT_UNKNOWN;
struct rte_pci_addr addr;
if (pci.length() == 0) {
if (port_id >= RTE_MAX_ETHPORTS) {
return pb_error(EINVAL, "Invalid port id %d", port_id);
}
if (!rte_eth_devices[port_id].attached) {
return pb_error(ENODEV, "Port id %d is not available", port_id);
}
} else {
struct rte_pci_addr addr;
if (port_id != DPDK_PORT_UNKNOWN) {
return pb_error(EINVAL,
"You cannot specify both "
"'port_id' and 'pci' fields");
}
if (eal_parse_pci_DomBDF(pci.c_str(), &addr) != 0 &&
eal_parse_pci_BDF(pci.c_str(), &addr) != 0) {
return pb_error(EINVAL,
"PCI address must be like "
"dddd:bb:dd.ff or bb:dd.ff");
}
for (int i = 0; i < RTE_MAX_ETHPORTS; i++) {
if (!rte_eth_devices[i].attached || !rte_eth_devices[i].pci_dev ||
rte_eal_compare_pci_addr(&addr, &rte_eth_devices[i].pci_dev->addr)) {
continue;
}
return pb_error(EINVAL, "No PCI address specified");
}
port_id = i;
break;
if (eal_parse_pci_DomBDF(pci.c_str(), &addr) != 0 &&
eal_parse_pci_BDF(pci.c_str(), &addr) != 0) {
return pb_error(EINVAL,
"PCI address must be like "
"dddd:bb:dd.ff or bb:dd.ff");
}
for (int i = 0; i < RTE_MAX_ETHPORTS; i++) {
if (!rte_eth_devices[i].attached || !rte_eth_devices[i].pci_dev ||
rte_eal_compare_pci_addr(&addr, &rte_eth_devices[i].pci_dev->addr)) {
continue;
}
/* If not found, maybe the device has not been attached yet */
if (port_id == DPDK_PORT_UNKNOWN) {
char name[RTE_ETH_NAME_MAX_LEN];
int ret;
port_id = i;
break;
}
snprintf(name, RTE_ETH_NAME_MAX_LEN, "%04x:%02x:%02x.%02x", addr.domain,
addr.bus, addr.devid, addr.function);
/* If not found, maybe the device has not been attached yet */
if (port_id == DPDK_PORT_UNKNOWN) {
char name[RTE_ETH_NAME_MAX_LEN];
int ret;
ret = rte_eth_dev_attach(name, &port_id);
snprintf(name, RTE_ETH_NAME_MAX_LEN, "%04x:%02x:%02x.%02x", addr.domain,
addr.bus, addr.devid, addr.function);
if (ret < 0) {
return pb_error(ENODEV,
"Cannot attach PCI "
"device %s",
name);
}
ret = rte_eth_dev_attach(name, &port_id);
*ret_hot_plugged = true;
if (ret < 0) {
return pb_error(ENODEV,
"Cannot attach PCI "
"device %s",
name);
}
*ret_hot_plugged = true;
}
if (port_id == DPDK_PORT_UNKNOWN && vdev.length() != 0) {
const char *name = vdev.c_str();
int ret = rte_eth_dev_attach(name, &port_id);
*ret_port_id = port_id;
return pb_errno(0);
}
if (ret < 0) {
return pb_error(ENODEV, "Cannot attach vdev %s", name);
}
// Find a DPDK vdev by name.
// returns 0 and sets *ret_port_id to the port_id of "vdev" if it is valid and
// available. *ret_hot_plugged is set to true if the device was attached to
// DPDK as a result of calling this function.
// returns > 0 on error.
static pb_error_t find_dpdk_vdev(const std::string &vdev,
dpdk_port_t *ret_port_id,
bool *ret_hot_plugged) {
dpdk_port_t port_id = DPDK_PORT_UNKNOWN;
*ret_hot_plugged = true;
if (vdev.length() == 0) {
return pb_error(EINVAL, "No vdev specified");
}
if (port_id == DPDK_PORT_UNKNOWN) {
return pb_error(EINVAL,
"'port_id', 'pci', or 'vdev' field "
"must be specified");
const char *name = vdev.c_str();
int ret = rte_eth_dev_attach(name, &port_id);
if (ret < 0) {
return pb_error(ENODEV, "Cannot attach vdev %s", name);
}
*ret_hot_plugged = true;
*ret_port_id = port_id;
return pb_errno(0);
}
pb_error_t PMDPort::Init(const bess::pb::PMDPortArg &arg) {
dpdk_port_t ret_port_id = -1;
dpdk_port_t ret_port_id = DPDK_PORT_UNKNOWN;
struct rte_eth_dev_info dev_info;
struct rte_eth_conf eth_conf;
......@@ -201,13 +223,32 @@ pb_error_t PMDPort::Init(const bess::pb::PMDPortArg &arg) {
int i;
pb_error_t err = find_dpdk_port(
arg.pci().length() != 0 ? DPDK_PORT_UNKNOWN : arg.port_id(), arg.pci(),
arg.vdev(), &ret_port_id, &hot_plugged_);
pb_error_t err;
switch (arg.port_case()) {
case bess::pb::PMDPortArg::kPortId: {
err = find_dpdk_port_by_id(arg.port_id(), &ret_port_id);
break;
}
case bess::pb::PMDPortArg::kPci: {
err = find_dpdk_port_by_pci_addr(arg.pci(), &ret_port_id, &hot_plugged_);
break;
}
case bess::pb::PMDPortArg::kVdev: {
err = find_dpdk_vdev(arg.vdev(), &ret_port_id, &hot_plugged_);
break;
}
default:
return pb_error(EINVAL, "No port specified");
}
if (err.err() != 0) {
return err;
}
if (ret_port_id == DPDK_PORT_UNKNOWN) {
return pb_error(ENOENT, "Port not found");
}
eth_conf = default_eth_conf();
if (arg.loopback()) {
eth_conf.lpbk_mode = 1;
......
......@@ -17,7 +17,7 @@ static inline int is_valid_gate(gate_idx_t gate) {
const Commands IPLookup::cmds = {
{"add", "IPLookupCommandAddArg", MODULE_CMD_FUNC(&IPLookup::CommandAdd), 0},
{"clear", "EmptyArg", MODULE_CMD_FUNC(&IPLookup::CommandAdd), 0}};
{"clear", "EmptyArg", MODULE_CMD_FUNC(&IPLookup::CommandClear), 0}};
pb_error_t IPLookup::Init(const bess::pb::EmptyArg &) {
struct rte_lpm_config conf = {
......
......@@ -70,10 +70,18 @@ pb_cmd_response_t Measure::CommandGetSummary(const bess::pb::EmptyArg &) {
pb_cmd_response_t response;
bess::pb::MeasureCommandGetSummaryResponse r;
summarize_hist(&hist_, &summary_);
reset_hist(&hist_);
r.set_timestamp(get_epoch_time());
r.set_packets(pkt_total);
r.set_bits(bits);
r.set_total_latency_ns(total_latency_ * 100);
r.set_latency_min_ns(summary_.min);
r.set_latency_avg_ns(summary_.avg);
r.set_latency_max_ns(summary_.max);
r.set_latency_50_ns(summary_.latencies[1]);
r.set_latency_99_ns(summary_.latencies[2]);
response.mutable_error()->set_err(0);
response.mutable_other()->PackFrom(r);
......
......@@ -12,6 +12,7 @@ class Measure final : public Module {
Measure()
: Module(),
hist_(),
summary_(),
start_time_(),
warmup_(),
pkt_cnt_(),
......@@ -26,6 +27,7 @@ class Measure final : public Module {
private:
struct histogram hist_;
struct hist_summary summary_;
uint64_t start_time_;
int warmup_; /* second */
......
......@@ -45,6 +45,10 @@ pb_cmd_response_t Rewrite::CommandAdd(const bess::pb::RewriteArg &arg) {
}
num_templates_ = curr + arg.templates_size();
if(num_templates_ == 0){
set_cmd_response_error(&response, pb_errno(0));
return response;
}
for (size_t i = num_templates_; i < kNumSlots; i++) {
size_t j = i % num_templates_;
......
......@@ -54,14 +54,27 @@ pb_error_t SetMetadata::AddAttrOne(
bess::metadata::kMetadataAttrMaxSize);
}
if (attr.value() != 0) {
if (uint64_to_bin((uint8_t *)&value, size, attr.value(),
if (attr.value_case() == bess::pb::SetMetadataArg_Attribute::kValueInt) {
if (uint64_to_bin((uint8_t *)&value, size, attr.value_int(),
bess::utils::is_be_system())) {
return pb_error(EINVAL,
"'value' field has not a "
"'value_int' field has not a "
"correct %lu-byte value",
size);
}
} else if (attr.value_case() ==
bess::pb::SetMetadataArg_Attribute::kValueHex) {
if (attr.value_hex().length() != size) {
return pb_error(EINVAL,
"'value_hex' field has not a "
"correct %lu-byte value",
size);
}
std::string value_hex(attr.value_hex());
if (!bess::utils::is_be_system()) {
std::reverse(value_hex.begin(), value_hex.end());
}
memcpy(&value, value_hex.data(), size);
} else {
offset = attr.offset();
if (offset < 0 || offset + size >= SNBUF_DATA) {
......
......@@ -26,8 +26,8 @@ pb_error_t Source::Init(const bess::pb::SourceArg &arg) {
if (arg.burst() > 0) {
if (arg.burst() > bess::PacketBatch::kMaxBurst) {
return pb_error(EINVAL, "burst size must be [1,%ld]",
bess::PacketBatch::kMaxBurst);
return pb_error(EINVAL, "burst size must be [0,%ld]",
bess::PacketBatch::kMaxBurst);
}
burst_ = arg.burst();
}
......@@ -39,14 +39,14 @@ pb_cmd_response_t Source::CommandSetBurst(
const bess::pb::SourceCommandSetBurstArg &arg) {
pb_cmd_response_t response;
uint64_t val = arg.burst();
if (val == 0 || val > bess::PacketBatch::kMaxBurst) {
if (arg.burst() > bess::PacketBatch::kMaxBurst) {
set_cmd_response_error(&response,
pb_error(EINVAL, "burst size must be [1,%lu]",
pb_error(EINVAL, "burst size must be [0,%lu]",
bess::PacketBatch::kMaxBurst));
return response;
}
burst_ = val;
burst_ = arg.burst();
set_cmd_response_error(&response, pb_errno(0));
return response;
}
......
......@@ -10,7 +10,7 @@ namespace bess {
void Scheduler::ScheduleLoop() {
uint64_t now;
// How many rounds to go before we do accounting.
const uint64_t accounting_mask = 0xffff;
const uint64_t accounting_mask = 0xff;
static_assert(((accounting_mask + 1) & accounting_mask) == 0,
"Accounting mask must be (2^n)-1");
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment