Skip to content
Merged

Dev #379

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
076fdb7
Potential fix for code scanning alert no. 4558: Time-of-check time-of…
GIC-de Jan 29, 2026
44b42ac
check RA autonomous prefix flag (#371)
GIC-de Feb 24, 2026
37b3763
fix DHCPv6 short lease time corner case
GIC-de Feb 25, 2026
c933783
add BNG Blaster config schema
GIC-de Feb 25, 2026
8b7860b
fix example config
GIC-de Feb 25, 2026
905ae9f
fix config docs
GIC-de Feb 25, 2026
e792f23
fix typo in ISIS
GIC-de Feb 25, 2026
2477f00
fix format in config parser
GIC-de Feb 25, 2026
68dc984
add config to change tun name (#375)
GIC-de Feb 25, 2026
0932515
add IO modes to schema
GIC-de Feb 26, 2026
8815de3
add stream iterators/counts
GIC-de Feb 26, 2026
7a20d3c
DPDK enhancements
GIC-de Feb 27, 2026
ab8d74a
DPDK install update
GIC-de Feb 27, 2026
2af6ecb
API enahncements
GIC-de Feb 27, 2026
40450c8
cmd arg schema
GIC-de Mar 2, 2026
a9fd3f8
stream summary cmd traffic stats
GIC-de Mar 2, 2026
e32dda5
add session summary cmd
GIC-de Mar 2, 2026
171dcf7
docu fix
GIC-de Mar 2, 2026
f052205
fix build errors
GIC-de Mar 2, 2026
90d67da
fix MPLS markings for A10NSP
GIC-de Mar 2, 2026
42e2fe3
update session/stream commands
GIC-de Mar 5, 2026
f8acc1a
add missing documentation as well as set pcp for ARP and ICMPv6 ND/RS…
Mar 3, 2026
6389d32
docs update
GIC-de Mar 5, 2026
3df5c73
fix stream ctrl command
GIC-de Mar 5, 2026
6dd61d9
add config for LI udp port
GIC-de Mar 5, 2026
8439a06
fix regression tests
GIC-de Mar 5, 2026
7ec2ca4
CLI error message
GIC-de Mar 5, 2026
ffe2f4c
fix regression tests
GIC-de Mar 5, 2026
ef19a5e
fix stream/flow API
GIC-de Mar 10, 2026
8498592
fix access interface dhcpv6-ldra config
GIC-de Mar 24, 2026
1c5bafe
fix docs/table
GIC-de Mar 24, 2026
3eccc7b
github pages
GIC-de Mar 24, 2026
000ebc8
fix LAG member distribution of stream flows
GIC-de Mar 25, 2026
a0f5e49
fix a10nsp dynamic interfaces
GIC-de Mar 26, 2026
941fcd9
fix ncurses ui
GIC-de Mar 26, 2026
61adc84
remove LI ncourses workaround
GIC-de Mar 26, 2026
6224ed6
fix ncourses log
GIC-de Mar 26, 2026
81522a0
update docs for a10nsp-dynamic
GIC-de Mar 26, 2026
35a5d50
github pages
GIC-de Mar 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 36 additions & 17 deletions code/bngblaster-cli
Original file line number Diff line number Diff line change
Expand Up @@ -39,50 +39,69 @@ Examples:
sys.exit(1)


def main():
"""main function"""
def build_request(argv):
request = {}
if(len(sys.argv)) < 3:
usage()

socket_path = sys.argv[1]

request["command"] = sys.argv[2]
if(len(sys.argv)) > 4:
request["command"] = argv[2]
if(len(argv)) > 4:
request["arguments"] = {}
for i in range(3, len(sys.argv), 2):
arg = sys.argv[i+1]
for i in range(3, len(argv), 2):
arg = argv[i+1]
try:
# integer arguments like "session-id 1"
request["arguments"][sys.argv[i]] = int(arg)
request["arguments"][argv[i]] = int(arg)
except:
try:
# list arguments like "sessions [1,2]""
request["arguments"][sys.argv[i]] = ast.literal_eval(arg)
request["arguments"][argv[i]] = ast.literal_eval(arg)
except:
# string arguments like "group 239.0.0.1"
request["arguments"][sys.argv[i]] = arg
#print(json.dumps(request).encode('utf-8'))
request["arguments"][argv[i]] = arg
return request


def send_request(socket_path, request):
if os.path.exists(socket_path):
client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
client.connect(socket_path)
client.send(json.dumps(request).encode('utf-8'))

data = ""
while True:
junk = client.recv(1024)
if junk:
data += junk.decode('utf-8')
else:
break
print(json.dumps(json.loads(data), indent=4))
return json.loads(data)
except Exception as e:
error(e)
finally:
client.close()
else:
error("socket %s not found" % socket_path)


def main():
"""main function"""
if(len(sys.argv)) < 3:
usage()
if sys.argv[2] == "help":
usage()

socket_path = sys.argv[1]
try:
request = build_request(sys.argv)
except Exception as e:
error("invalid command")
#print(json.dumps(request).encode('utf-8'))
data = send_request(socket_path, request)

if sys.argv[2] == "commands":
for cmd in data["commands"]:
print("%s %s" % (cmd["command"], str(cmd["arguments"]).replace("', '", "|").replace("'", "")))
else:
print(json.dumps(data, indent=4))


if __name__ == "__main__":
main()
24 changes: 14 additions & 10 deletions code/bngblaster/src/bbl_a10nsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,7 @@ bbl_a10nsp_dynamic(bbl_a10nsp_interface_s *interface,

bbl_lag_s *lag;
bbl_lag_member_s *member;
io_handle_s *io_new;
uint8_t key;

while(stream) {
Expand All @@ -784,22 +785,18 @@ bbl_a10nsp_dynamic(bbl_a10nsp_interface_s *interface,
LOG(DEBUG, "A10NSP (ID: %u) Change TX interface of stream %lu from %s to %s\n",
session->session_id, stream->flow_id, stream->tx_a10nsp_interface->name, interface->name);

stream->tx_a10nsp_interface = interface;
stream->io->update_streams = true;
stream->update_pps = true;

if(stream->lag) {
/* Remove stream from LAG interface */
lag = stream->tx_a10nsp_interface->interface->lag;
stream_next = lag->stream_head;
stream_prev = NULL;
while(stream_next) {
if(stream_next == stream) {
lag->stream_count--;
if(lag->stream_count) lag->stream_count--;
if(stream_prev) {
stream_prev->lag_next = stream->lag_next;
} else {
lag->stream_head = stream_next;
lag->stream_head = stream->lag_next;
}
stream->lag = false;
stream->lag_next = NULL;
Expand All @@ -810,6 +807,7 @@ bbl_a10nsp_dynamic(bbl_a10nsp_interface_s *interface,
}
}
}
stream->tx_a10nsp_interface = interface;

/* Move stream */
if(interface->interface->type == LAG_INTERFACE) {
Expand All @@ -819,17 +817,23 @@ bbl_a10nsp_dynamic(bbl_a10nsp_interface_s *interface,
lag->stream_head = stream;
lag->stream_count++;
if(lag->active_count) {
key = stream->flow_id % lag->active_count;
key = rand() % lag->active_count;
member = lag->active_list[key];
} else {
member = CIRCLEQ_FIRST(&lag->lag_member_qhead);
}
stream->io = member->interface->io.tx;
stream->tx_interface = member->interface;
io_new = member->interface->io.tx;
stream->tx_interface = lag->interface;
} else {
stream->io = interface->interface->io.tx;
io_new = interface->interface->io.tx;
stream->tx_interface = interface->interface;
}
if(stream->io) {
stream->update_pps = true;
stream->io->update_streams = true;
} else {
io_stream_add(io_new, stream);
}
}
}
stream = stream->session_next;
Expand Down
21 changes: 13 additions & 8 deletions code/bngblaster/src/bbl_access.c
Original file line number Diff line number Diff line change
Expand Up @@ -542,15 +542,20 @@ bbl_access_rx_icmpv6(bbl_access_interface_s *interface,
/* The first RA received ... */
session->icmpv6_ra_received = true;
if(icmpv6->prefix.len) {
memcpy(&session->ipv6_prefix, &icmpv6->prefix, sizeof(ipv6_prefix));
*(uint64_t*)&session->ipv6_address[0] = *(uint64_t*)session->ipv6_prefix.address;
*(uint64_t*)&session->ipv6_address[8] = session->ip6cp_ipv6_identifier;
if(session->access_type == ACCESS_TYPE_PPPOE) {
ACTIVATE_ENDPOINT(session->endpoint.ipv6);
if(icmpv6->prefix_flags & ICMPV6_PREFIX_FLAGS_AUTONOMOUS) {
memcpy(&session->ipv6_prefix, &icmpv6->prefix, sizeof(ipv6_prefix));
*(uint64_t*)&session->ipv6_address[0] = *(uint64_t*)session->ipv6_prefix.address;
*(uint64_t*)&session->ipv6_address[8] = session->ip6cp_ipv6_identifier;
if(session->access_type == ACCESS_TYPE_PPPOE) {
ACTIVATE_ENDPOINT(session->endpoint.ipv6);
}
session->version++;
LOG(IP, "IPv6 (ID: %u) ICMPv6 RA prefix %s/%d\n",
session->session_id, format_ipv6_address(&session->ipv6_prefix.address), session->ipv6_prefix.len);
} else {
LOG(IP, "IPv6 (ID: %u) ICMPv6 RA prefix %s/%d ignored because of missing autonomous flag\n",
session->session_id, format_ipv6_address(&session->ipv6_prefix.address), session->ipv6_prefix.len);
}
session->version++;
LOG(IP, "IPv6 (ID: %u) ICMPv6 RA prefix %s/%d\n",
session->session_id, format_ipv6_address(&session->ipv6_prefix.address), session->ipv6_prefix.len);
if(icmpv6->dns1) {
memcpy(&session->ipv6_dns1, icmpv6->dns1, IPV6_ADDR_LEN);
if(icmpv6->dns2) {
Expand Down
63 changes: 57 additions & 6 deletions code/bngblaster/src/bbl_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ const char g_default_system_id[] = "0100.1001.0010";
const char g_default_area[] = "49.0001/24";
const char g_default_ospf_area[] = "0.0.0.0";

extern uint16_t g_li_udp_port;

#define JSON_OBJ_GET_BOOL(_json, _val, _section, _key) \
do { \
_val = json_object_get(_json, _key); \
Expand Down Expand Up @@ -976,7 +978,6 @@ json_parse_network_interface(json_t *network_interface, bbl_network_config_s *ne
} else if(strcmp(s, "broadcast") == 0) {
network_config->ospfv2_type = OSPF_INTERFACE_BROADCAST;
} else {

return false;
}
} else {
Expand Down Expand Up @@ -2016,7 +2017,7 @@ json_parse_isis_config(json_t *isis, isis_config_s *isis_config)
for(i = 0; i < isis_config->sr_algo_count; i++) {
sub = json_array_get(value, i);
if(json_is_number(sub)) {
isis_config->sr_algo[i] = json_number_value(sub);
isis_config->sr_algo[i] = json_number_value(sub);
}
}
} else if(json_is_number(value)) {
Expand Down Expand Up @@ -2479,9 +2480,10 @@ json_parse_stream(json_t *stream, bbl_stream_config_s *stream_config)
const char *schema[] = {
"name", "stream-group-id", "type", "autostart",
"direction", "network-interface", "a10nsp-interface",
"source-port", "destination-port", "length", "ttl",
"source-port", "source-port-max", "source-port-step",
"destination-port", "destination-port-max", "destination-port-step",
"priority", "vlan-priority", "inner-vlan-priority",
"pps", "bps", "Kbps", "Mbps",
"pps", "bps", "Kbps", "Mbps", "length", "ttl", "count",
"pps-upstream", "bps-upstream", "Kbps-upstream", "Mbps-upstream",
"Gbps", "max-packets", "start-delay",
"ldp-ipv4-lookup-address", "ldp-ipv6-lookup-address",
Expand Down Expand Up @@ -2568,19 +2570,55 @@ json_parse_stream(json_t *stream, bbl_stream_config_s *stream_config)
return false;
}

JSON_OBJ_GET_NUMBER(stream, value, "stream", "count", 1, 65535);
if(value) {
stream_config->count = json_number_value(value);
} else {
stream_config->count = 1;
}
JSON_OBJ_GET_NUMBER(stream, value, "stream", "source-port", 0, 65535);
if(value) {
stream_config->src_port = json_number_value(value);
} else {
stream_config->src_port = BBL_UDP_PORT;
}
stream_config->src_port_min = stream_config->src_port;
JSON_OBJ_GET_NUMBER(stream, value, "stream", "source-port-step", 0, 65535);
if(value) {
stream_config->src_port_step = json_number_value(value);
}
JSON_OBJ_GET_NUMBER(stream, value, "stream", "source-port-max", 0, 65535);
if(value) {
stream_config->src_port_max = json_number_value(value);
} else {
stream_config->src_port_max = 65535;
}
if(stream_config->src_port_min > stream_config->src_port_max) {
fprintf(stderr, "JSON config error: Invalid value for stream->source-port (source-port > source-port-max)\n");
return false;
}

JSON_OBJ_GET_NUMBER(stream, value, "stream", "destination-port", 0, 65535);
if(value) {
stream_config->dst_port = json_number_value(value);
} else {
stream_config->dst_port = BBL_UDP_PORT;
}
stream_config->dst_port_min = stream_config->dst_port;
JSON_OBJ_GET_NUMBER(stream, value, "stream", "destination-port-step", 0, 65535);
if(value) {
stream_config->dst_port_step = json_number_value(value);
}
JSON_OBJ_GET_NUMBER(stream, value, "stream", "destination-port-max", 0, 65535);
if(value) {
stream_config->dst_port_max = json_number_value(value);
} else {
stream_config->dst_port_max = 65535;
}
if(stream_config->dst_port_min > stream_config->dst_port_max) {
fprintf(stderr, "JSON config error: Invalid value for stream->destination-port (destination-port > destination-port-max)\n");
return false;
}

JSON_OBJ_GET_NUMBER(stream, value, "stream", "length", 76, 9000);
if(value) {
Expand Down Expand Up @@ -3902,7 +3940,8 @@ json_parse_config(json_t *root)
"stream-burst-ms",
"reassemble-fragments",
"multicast-autostart",
"udp-checksum"
"udp-checksum",
"li-udp-port"
};
if(!schema_validate(section, "traffic", schema,
sizeof(schema)/sizeof(schema[0]))) {
Expand Down Expand Up @@ -3945,6 +3984,10 @@ json_parse_config(json_t *root)
if(value) {
g_ctx->config.stream_udp_checksum = json_boolean_value(value);
}
JSON_OBJ_GET_NUMBER(section, value, "traffic", "li-udp-port", 0, 65535);
if(value) {
g_li_udp_port = json_number_value(value);
}
}

/* Session Traffic Configuration */
Expand Down Expand Up @@ -4118,7 +4161,7 @@ json_parse_config(json_t *root)

const char *schema[] = {
"io-mode", "io-slots", "io-burst", "qdisc-bypass",
"tx-interval", "rx-interval", "tx-threads",
"tx-interval", "rx-interval", "tx-threads", "tun-name",
"rx-threads", "capture-include-streams", "mac-modifier",
"lag", "network", "access", "a10nsp", "links", "a10nsp-dynamic"
};
Expand Down Expand Up @@ -4191,6 +4234,13 @@ json_parse_config(json_t *root)
if(value) {
g_ctx->config.a10nsp_dynamic = json_boolean_value(value);
}
if(json_unpack(section, "{s:s}", "tun-name", &s) == 0) {
if(strlen(s) > 10) {
fprintf(stderr, "JSON config error: Invalid value for interfaces->tun-name (string length > 10)\n");
return false;
}
g_ctx->config.tun_name = strdup(s);
}
/* LAG Configuration Section */
sub = json_object_get(section, "lag");
if(json_is_array(sub)) {
Expand Down Expand Up @@ -4669,6 +4719,7 @@ bbl_config_init_defaults()
g_ctx->config.io_burst = 256;
g_ctx->config.io_max_stream_len = 9000;
g_ctx->config.qdisc_bypass = true;
g_ctx->config.tun_name = "bbl";
g_ctx->config.sessions = 1;
g_ctx->config.sessions_max_outstanding = 800;
g_ctx->config.sessions_start_period_ns = 2500000; /* 400/s */
Expand Down
Loading
Loading