Skip to content

Commit 7c82b52

Browse files
committed
fixed AppendDestination, still need to check if it makes a double
1 parent 230b512 commit 7c82b52

File tree

4 files changed

+119
-71
lines changed

4 files changed

+119
-71
lines changed

mptcpanalyzer/cli.py

+22-12
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,9 @@ def do_tcp_summary(self, args, unknown):
529529
# print(args)
530530

531531
for dest in ConnectionRoles:
532+
# TODO do it only when needed
533+
# con = TcpConnection.build_from_dataframe(df, tcpstreamid)
534+
# df2 = tcpdest_from_connections(df, con)
532535
res = tcp_get_stats(
533536
self.data, args.tcpstream,
534537
dest,
@@ -737,8 +740,9 @@ def do_summary_extended(self, args, unknown):
737740
# TODO print subflow
738741
msg = inspect.cleandoc("""
739742
tcpstream {sf.tcpstreamid} analysis:
740-
- throughput: transferred {sf.throughput_bytes} out of {mptcp.mptcp_throughput_bytes}, accounting for {mptcp_tput_ratio:.2f}%
741-
- goodput: transferred {sf.mptcp_goodput_bytes} out of {mptcp.mptcp_goodput_bytes}, accounting for {mptcp_gput_ratio:.2f}%""")
743+
- throughput: transferred {sf.throughput_bytes} out of {mptcp.mptcp_throughput_bytes} mptcp bytes, accounting for {mptcp_tput_ratio:.2f}% of MPTCP throughput
744+
- goodput: transferred {sf.mptcp_goodput_bytes} out of {mptcp.mptcp_goodput_bytes}, accounting for {mptcp_gput_ratio:.2f}% of MPTCP goodput
745+
""")
742746

743747
# print(subflow)
744748
self.poutput(
@@ -897,6 +901,12 @@ def do_qualify_reinjections(self, args, unknown):
897901
898902
TODO move the code into a proper function
899903
"""
904+
905+
print("Qualifying reinjections for stream in destination:")
906+
# destinations = [ ConnectionRoles.Server ]
907+
destinations = args.pcap_destinations
908+
print("Looking at destinations %s" % destinations)
909+
900910
# TODO this should be done automatically right ?
901911
df_all = load_merged_streams_into_pandas(
902912
args.pcap1,
@@ -925,10 +935,10 @@ def _print_reinjection_comparison(original_packet, reinj, ):
925935
# original_packet = sender_df.loc[ sender_df.packetid == initial_packetid, ].iloc[0]
926936
row = reinj
927937

928-
reinjection_packetid = getattr(row, _sender("packetid")),
929-
reinjection_start = getattr(row, _sender("abstime")),
930-
reinjection_arrival = getattr(row, _receiver("abstime")),
931-
original_start = original_packet[_sender("abstime")],
938+
reinjection_packetid = getattr(row, _sender("packetid"))
939+
reinjection_start = getattr(row, _sender("abstime"))
940+
reinjection_arrival = getattr(row, _receiver("abstime"))
941+
original_start = original_packet[_sender("abstime")]
932942
original_arrival = original_packet[_receiver("abstime")]
933943

934944
if reinj.redundant == False:
@@ -983,15 +993,14 @@ def _print_reinjection_comparison(original_packet, reinj, ):
983993
)
984994
return
985995

986-
for destination in ConnectionRoles:
987-
988-
if args.destinations and destination not in args.destinations:
989-
log.debug("ignoring destination %s " % destination)
990-
continue
996+
# TODO use args.mptcp_destinations instead
997+
# TODO revert
998+
# destinations = [ ConnectionRoles.Server ]
999+
for destination in destinations:
9911000

9921001
self.poutput("looking for reinjections towards mptcp %s" % destination)
9931002
sender_df = df[df.mptcpdest == destination]
994-
log.debug("%d reinjections in that direction" % (len(sender_df), ))
1003+
log.debug("%d packets in that direction" % (len(sender_df), ))
9951004

9961005
# TODO we now need to display successful reinjections
9971006
reinjections = sender_df[pd.notnull(sender_df[_sender("reinjection_of")])]
@@ -1019,6 +1028,7 @@ def _print_reinjection_comparison(original_packet, reinj, ):
10191028
parser = MpTcpAnalyzerParser(
10201029
description="Listing reinjections of the connection"
10211030
)
1031+
# action= filter_stream
10221032
parser.add_argument("mptcpstream", type=MpTcpStreamId, help="mptcp.stream id")
10231033
parser.add_argument("--summary", action="store_true", default=False,
10241034
help="Just count reinjections")

mptcpanalyzer/data.py

+13-4
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,6 @@ def _gen_converters() -> Dict[str, Callable]:
285285
for name, converter in default_converters.items():
286286
converters.update({_first(name): converter, _second(name): converter})
287287

288-
289288
return converters
290289

291290
with open(cachename) as fd:
@@ -310,6 +309,14 @@ def _gen_converters() -> Dict[str, Callable]:
310309
# at this stage, destinatiosn are nan
311310
# debug_dataframe(merged_df, "Merged dataframe", )
312311

312+
# workaround bug https://github.com/pandas-dev/pandas/issues/25448
313+
def _convert_to_enums():
314+
# per_pcap_artificial_fields
315+
for col in [ _first("tcpdest"), _first("mptcpdest"), _second("tcpdest"), _second("mptcpdest")]:
316+
merged_df[col] = merged_df[col].apply(_convert_role, convert_dtype=False)
317+
318+
# df[]
319+
313320
# log.debug("Column names after loading from cache: %s", merged_df.columns)
314321

315322
# we fix the clocks a posteriori so that the cache is still usable
@@ -638,7 +645,7 @@ def _rename_column(col_name, suffixes) -> str:
638645
# subdf[ _first("tcpdest") == ConnectionRole.Client] .rename(columns=_rename_cols, inplace=True)
639646
# print(subdf.columns)
640647
# print(total.columns)
641-
debug_dataframe(total, "total")
648+
# debug_dataframe(total, "total")
642649

643650
logging.debug("Converted to sender/receiver format")
644651
return total
@@ -1173,6 +1180,7 @@ def classify_reinjections(df_all: pd.DataFrame) -> pd.DataFrame:
11731180
Returns
11741181
a new dataframe with an added column "redundant"
11751182
"""
1183+
log.debug("Classifying reinjections")
11761184

11771185
df_all["redundant"] = False
11781186
df_all["reinj_delta"] = np.nan
@@ -1187,6 +1195,7 @@ def classify_reinjections(df_all: pd.DataFrame) -> pd.DataFrame:
11871195

11881196
for destination in ConnectionRoles:
11891197

1198+
log.debug("Looking at mptcp destination %r" % destination)
11901199
sender_df = df[df.mptcpdest == destination]
11911200

11921201
# print(sender_df[ sender_df.reinjected_in.notna() ][["packetid", "reinjected_in"]])
@@ -1198,7 +1207,7 @@ def classify_reinjections(df_all: pd.DataFrame) -> pd.DataFrame:
11981207
# print(sender_df["reinjection_of"])
11991208
reinjected_packets = sender_df.dropna(axis='index', subset=[_sender("reinjection_of")])
12001209

1201-
logging.debug("%d reinjected packets" % len(reinjected_packets))
1210+
log.debug("%d reinjected packets" % len(reinjected_packets))
12021211
# with pd.option_context('display.max_rows', None, 'display.max_columns', 300):
12031212
# print(reinjected_packets[
12041213
# _sender(["packetid", "reinjected_in", "reinjection_of"]) + _receiver(["reinjected_in", "reinjection_of"])
@@ -1230,7 +1239,7 @@ def classify_reinjections(df_all: pd.DataFrame) -> pd.DataFrame:
12301239

12311240
if original_packet.merge_status != "both":
12321241
# TODO count missed classifications ?
1233-
logging.debug("Original packet %d could not be mapped, giving up..." % (original_packet.packetid))
1242+
log.debug("Original packet %d could not be mapped, giving up..." % (original_packet.packetid))
12341243
continue
12351244

12361245
orig_arrival = getattr(original_packet, _receiver("reltime"))

mptcpanalyzer/parser.py

+50-36
Original file line numberDiff line numberDiff line change
@@ -180,13 +180,13 @@ class AppendDestination(DataframeAction):
180180
assume convention on naming
181181
TODO check if it's ok with FilterDest
182182
"""
183-
184183
def __init__(self, *args, **kwargs) -> None:
185184
self.already_called = False
186-
# self.destinations = list(ConnectionRoles)
185+
self.destinations = list(ConnectionRoles)
187186
# default=list(ConnectionRoles),
188187
super().__init__(
189-
*args, choices=CustomConnectionRolesChoices([e.name for e in ConnectionRoles]),
188+
*args,
189+
choices=CustomConnectionRolesChoices([e.name for e in ConnectionRoles]),
190190
default = list(ConnectionRoles), **kwargs)
191191

192192

@@ -198,11 +198,17 @@ def __call__(self, parser, namespace, values, option_string=None):
198198
# TODO change the default ?
199199
# setattr(namespace, self.dest, [])
200200
print("Already set")
201+
print("setting value %r" % values)
202+
# print("setting value %r" % self.destinations)
201203
# to make it unique
202-
self.destinations= list(set(self.destinations.append(values)))
204+
self.destinations.append(values)
205+
self.destinations= list(set(self.destinations))
206+
print("new result %r" % self.destinations)
203207
else:
204-
self.destinations = values
208+
print("Received first value %s" % values)
209+
self.destinations = [values]
205210

211+
self.already_called = True
206212
# df_name + "destinations"
207213
setattr(namespace, self.dest, self.destinations)
208214
# pcap1 = getattr(namespace, self.df_name + "1")
@@ -332,11 +338,11 @@ def __init__(self, df_name: str, **kwargs) -> None:
332338

333339
# assert self.field == "tcpdest" or self.field == "mptcpdest"
334340
# self.mptcp = mptcp
335-
# self.seen
341+
# self.seen
336342
# init with all destinations
337343
self.destinations = list(ConnectionRoles)
338344
self.already_called = False
339-
# TODO it could set choices automatically
345+
# TODO it could set choices automatically
340346
super().__init__(df_name, **kwargs)
341347

342348
def __call__(self, parser, namespace, values, option_string=None):
@@ -454,6 +460,41 @@ def gen_bicap_parser(protocol, dest=False):
454460
# protocol=protocol,
455461
return gen_pcap_parser(input_pcaps=input_pcaps, direction=dest)
456462

463+
# argparse_completer.ACArgumentParser
464+
class MpTcpAnalyzerParser(argparse_completer.ACArgumentParser):
465+
'''
466+
Wrapper around cmd2 argparse completer
467+
Should allow to switch backends easily.
468+
Also allows to do some postprocessing once the arguments are parsed
469+
like loading dataframes etc
470+
471+
'''
472+
473+
# def _parse_known_args(self, arg_strings, namespace):
474+
def parse_known_args(self, args=None, namespace=None):
475+
"""
476+
override it just to postprocess arguments
477+
"""
478+
479+
# returns a 2-item tuple
480+
known, unknown = super().parse_known_args(args, namespace)
481+
# print("res", res)
482+
483+
# TODO call filter_dataframe ?
484+
if getattr(known, "_dataframes", None):
485+
for name, df in known._dataframes.items():
486+
# print
487+
# so now we can filter the destination ?
488+
log.debug("dataframe [%s] in namespace" % name)
489+
else:
490+
log.debug("No dataframe in namespace")
491+
492+
# postprocessing for filtering destination
493+
494+
log.debug("MpTcpAnalyzerParser parser finished")
495+
# TODO pass along known, dataframes ?
496+
return (known, unknown)
497+
457498

458499
# map pcaps to a group
459500
def gen_pcap_parser(
@@ -464,7 +505,7 @@ def gen_pcap_parser(
464505
parents=[],
465506
# TODO get rid of this/skip-stream
466507
skip_subflows: bool = True,
467-
) -> argparse_completer.ACArgumentParser:
508+
) -> MpTcpAnalyzerParser:
468509
"""
469510
Generates a parser with common options.
470511
This parser can be completed or overridden by its children.
@@ -543,6 +584,7 @@ def _pcap(name, pcapAction="store", filterAction="store"):
543584
# choices=CustomConnectionRolesChoices([e.name for e in ConnectionRoles]),
544585
# TODO check how it works/FilterDest
545586
action=partial(AppendDestination, df_name),
587+
# action=partial(AppendDestination, df_name),
546588
# type parameter is a function/callable
547589
type=lambda x: ConnectionRoles.from_string(x),
548590
help='Filter flows according to their direction'
@@ -563,32 +605,4 @@ def _pcap(name, pcapAction="store", filterAction="store"):
563605
return parser
564606

565607

566-
# argparse_completer.ACArgumentParser
567-
class MpTcpAnalyzerParser(argparse_completer.ACArgumentParser):
568-
'''
569-
Wrapper around cmd2 argparse completer
570-
Should allow to switch backends easily.
571-
Also allows to do some postprocessing once the arguments are parsed
572-
like loading dataframes etc
573-
574-
'''
575-
576-
# def _parse_known_args(self, arg_strings, namespace):
577-
def parse_known_args(self, args=None, namespace=None):
578-
"""
579-
override it just to postprocess arguments
580-
"""
581-
res = super().parse_known_args(args, namespace)
582-
583-
# TODO call filter_dataframe ?
584-
if getattr(res, "_dataframes", None):
585-
for name, df in res._dataframes.items():
586-
# print
587-
# so now we can filter the destination ?
588-
pass
589-
590-
# postprocessing for filtering destination
591-
592-
logging.debug("MpTcpAnalyzerParser parser finished")
593-
return res
594608

0 commit comments

Comments
 (0)