traffic: add option to reanimate dying conversations
authorDouglas Bagnall <douglas.bagnall@catalyst.net.nz>
Mon, 22 Oct 2018 22:58:52 +0000 (11:58 +1300)
committerDouglas Bagnall <dbagnall@samba.org>
Tue, 8 Jan 2019 22:55:34 +0000 (23:55 +0100)
The traffic model is generated from a window in time, which makes
conversations appear to start and stop unnaturally at the window
boundaries. When the window is short compared to the traffic replay
time and the true expected conversation length, this has a significant
distorting effect, leading to more conversations than would be
expected to generate a given number of packets.

To offset this slightly we add the --conversation-persistence option
which tries to convert apparent death into a longish wait.

Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
python/samba/emulate/traffic.py
python/samba/tests/blackbox/testdata/traffic_replay-2.expected [new file with mode: 0644]
python/samba/tests/blackbox/traffic_replay.py
script/traffic_replay
selftest/knownfail.d/traffic [deleted file]

index 448cacfda41fe9e6623e3403086d43fec303a7b8..76c39efba56b89fdf7d189b30c7ac5dfc40beb4f 100644 (file)
@@ -1226,7 +1226,8 @@ class TrafficModel(object):
     def construct_conversation_sequence(self, timestamp=0.0,
                                         hard_stop=None,
                                         replay_speed=1,
-                                        ignore_before=0):
+                                        ignore_before=0,
+                                        persistence=0):
         """Construct an individual conversation packet sequence from the
         model.
         """
@@ -1238,7 +1239,15 @@ class TrafficModel(object):
         while True:
             p = random.choice(self.ngrams.get(key, (NON_PACKET,)))
             if p == NON_PACKET:
-                break
+                if timestamp < ignore_before:
+                    break
+                if random.random() > persistence:
+                    print("ending after %s (persistence %.1f)" % (key, persistence),
+                          file=sys.stderr)
+                    break
+
+                p = 'wait:%d' % random.randrange(5, 12)
+                print("trying %s instead of end" % p, file=sys.stderr)
 
             if p in self.query_details:
                 extra = random.choice(self.query_details[p])
@@ -1260,10 +1269,16 @@ class TrafficModel(object):
                     c.append((timestamp, protocol, opcode, extra))
 
             key = key[1:] + (p,)
+            if key[-2][:5] == 'wait:' and key[-1][:5] == 'wait:':
+                # two waits in a row can only be caused by "persistence"
+                # tricks, and will not result in any packets being found.
+                # Instead we pretend this is a fresh start.
+                key = (NON_PACKET,) * (self.n - 1)
 
         return c
 
-    def generate_conversation_sequences(self, scale, duration, replay_speed=1):
+    def generate_conversation_sequences(self, scale, duration, replay_speed=1,
+                                        persistence=0):
         """Generate a list of conversation descriptions from the model."""
 
         # We run the simulation for ten times as long as our desired
@@ -1280,7 +1295,8 @@ class TrafficModel(object):
             c = self.construct_conversation_sequence(start,
                                                      hard_stop=duration,
                                                      replay_speed=replay_speed,
-                                                     ignore_before=0)
+                                                     ignore_before=0,
+                                                     persistence=persistence)
             # will these "packets" generate actual traffic?
             # some (e.g. ldap unbind) will not generate anything
             # if the previous packets are not there, and if the
diff --git a/python/samba/tests/blackbox/testdata/traffic_replay-2.expected b/python/samba/tests/blackbox/testdata/traffic_replay-2.expected
new file mode 100644 (file)
index 0000000..7850a25
--- /dev/null
@@ -0,0 +1,17 @@
+0.011388       06              2       1       ldap    3       searchRequest   2       DC,DC           cn                      
+0.221447       06              2       1       ldap    2       unbindRequest                                                   
+0.460878       06              3       1       ldap    3       searchRequest   2       DC,DC           cn                      
+0.581933       11              4       1       cldap   3       searchRequest                           Netlogon                        
+0.596977       11              4       1       cldap   3       searchRequest                           Netlogon                        
+0.611184       11              4       1       cldap   3       searchRequest                           Netlogon                        
+0.666808       06              3       1       ldap    2       unbindRequest                                                   
+0.692730       11              5       1       cldap   3       searchRequest                           Netlogon                        
+0.692879       11              5       1       cldap   3       searchRequest                           Netlogon                        
+0.692946       11              5       1       cldap   3       searchRequest                           Netlogon                        
+0.744297       06              4       1       rpc_netlogon    29      NetrLogonGetDomainInfo  
+0.768994       06              4       1       kerberos                        
+0.772476       06              4       1       ldap    3       searchRequest   2       DC,DC           cn                      
+0.827760       06              5       1       rpc_netlogon    29      NetrLogonGetDomainInfo  
+0.828419       06              5       1       kerberos                        
+0.862850       06              5       1       ldap    3       searchRequest                           subschemaSubentry,dsServiceName,namingContexts,defaultNamingContext,schemaNamingContext,configurationNamingContext,rootDomainNamingContext,supportedControl,supportedLDAPVersion,supportedLDAPPolicies,supportedSASLMechanisms,dnsHostName,ldapServiceName,serverName,supportedCapabilities                     
+0.865384       06              6       1       ldap    3       searchRequest                           subschemaSubentry,dsServiceName,namingContexts,defaultNamingContext,schemaNamingContext,configurationNamingContext,rootDomainNamingContext,supportedControl,supportedLDAPVersion,supportedLDAPPolicies,supportedSASLMechanisms,dnsHostName,ldapServiceName,serverName,supportedCapabilities                     
index 4e9783ec51561fff36e579d4c397d9c6d2449fe9..8370939d243db5a25949117bbc554ae0c96aa76f 100644 (file)
@@ -70,6 +70,8 @@ class TrafficLearnerTests(BlackboxTestCase):
 
         for i, opts in enumerate((["--random-seed=3"],
                                   ["--random-seed=4"],
+                                  ["--random-seed=3",
+                                   "--conversation-persistence=0.5"],
                                   )):
             with temp_file(self.tempdir) as output:
                 command = ([SCRIPT, MODEL,
index b25476cae4a4d6dbfcaa86c7e4fbf7b150605ad1..a02539ffa7328f7373ca3985a05391074ad71b7f 100755 (executable)
@@ -88,6 +88,10 @@ def main():
                            help=('Wait this long for last packet to finish'))
     model_group.add_option('-r', '--replay-rate', type='float', default=1.0,
                            help='Replay the traffic faster by this factor')
+    model_group.add_option('--conversation-persistence', type='float',
+                           default=0.0,
+                           help=('chance (0 to 1) that a conversation waits '
+                                 'when it would have died'))
     model_group.add_option('--traffic-summary',
                            help=('Generate a traffic summary file and write '
                                  'it here (- for stdout)'))
@@ -262,7 +266,8 @@ def main():
             model.generate_conversation_sequences(
                 opts.scale_traffic,
                 opts.duration,
-                opts.replay_rate)
+                opts.replay_rate,
+                opts.conversation_persistence)
     else:
         conversations = []
 
diff --git a/selftest/knownfail.d/traffic b/selftest/knownfail.d/traffic
deleted file mode 100644 (file)
index 6fd6411..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-# This is in flux, so lets fail it for a while
-samba.tests.blackbox.traffic_replay.samba.tests.blackbox.traffic_replay.TrafficLearnerTests.test_summary_generation