Hi Risto Thank you so much for such a comprehensive and informative reply!
I'm just getting started with SEC but can already imagine a number of very useful applications of it. ________________________________ From: Risto Vaarandi <risto.vaara...@gmail.com> Sent: Friday, September 6, 2019 3:50 AM To: David Thomas <dtho...@kwiktrip.com> Cc: simple-evcorr-users@lists.sourceforge.net <simple-evcorr-users@lists.sourceforge.net> Subject: Re: [Simple-evcorr-users] Help calling perl to get hostname ATTENTION: This email originated from outside of Kwik Trip. Do not click links or open attachments unless you recognize the sender and know the content is safe. hi David, Kontakt David Thomas (<dtho...@kwiktrip.com<mailto:dtho...@kwiktrip.com>>) kirjutas kuupƤeval N, 5. september 2019 kell 21:37: Hello Risto: Last week you provided Clayton some advice on the rule below. I am the customer he was asking about this for. The rule is in place and working exactly as expected so thank you for your help. I need to take another step now. When the value of %TT is greater than 14400 and %+{tunnel} equal '241' I need to treat it differently. Our original idea was to have a second rule that monitored the events written by action2 below and then run an additional tcpsock if the conditions above were true. But as I'm learning how SEC works I'm wondering if it wouldn't be better to handle it all with just this one rule. I could have pattern2 call a sub that would figure out if the conditions above held or not and write a different version of the tcpsock in that case. Does that make sense, or would it be better to have the second separate rule. You can actually use both approaches, and your choice would largely depend on wider context and future plans for expanding the ruleset. For example, if you plan to implement a number of additional rules in near future for processing "neighbor Up" events, I would recommend to create separate rules for all those cases (including the current one), in order to make your ruleset more readable and manageable. However, if the current special case will remain the only one, you can also address it within the Pair rule that you already have. Since 2.7.0 version SEC supports the 'if' action which allows for conditional execution of action lists, and you can use it for addressing the special case for tunnel 241 by modifying the 'action2' field of the current rule. For example, consider the following Pair rule which executes different actions for tunnel 241 with long downtime, and all other events: type=Pair ptype=PerlFunc pattern=sub { my(%var); \ if ($_[0] !~ /neighbor \*?(\d+\.\d+\.\d+\.\d+) Down/) { return 0; } \ $var{"nip"} = $1; $var{"ts"} = time(); \ $var{"hostname"} = scalar gethostbyaddr(Socket::inet_aton($var{"nip"}), Socket::AF_INET); \ if (!defined($var{"hostname"})) { $var{"hostname"} = $var{"nip"} }; \ $var{"storenumber"} = "NA"; $var{"tunnel"} = "NA"; \ if ($var{"hostname"} =~ /(\d+)lo/) { $var{"storenumber"} = $1; } \ if ($var{"hostname"} =~ /lo(\d+)/) { $var{"tunnel"} = $1; } \ return \%var; } desc=BGP Neighbor $+{nip} Down action=tcpsock 10.3.0.85:514<http://10.3.0.85:514> LzEC BGP Neighbor status="Down" hostname="$+{hostname}" store="$+{storenumber}" tunnel="$+{tunnel}" ECRule="01-bgp-flap-detection" ECRulenum="1"%{.nl}; ptype2=RegExp pattern2=neighbor \*?$+{nip} Up desc2=BGP Neighbor %+{nip} Up action2=lcall %TT %+{ts} -> ( sub { time() - $_[0] } ); \ lcall %o %TT %+{tunnel} -> ( sub { $_[0] > 14400 && $_[1] eq "241" } ); \ if %o ( write - Event for hostname %+{hostname} store %+{storenumber} tunnel 241 downtime %TT ) \ else ( \ tcpsock 10.3.0.85:514<http://10.3.0.85:514> LzEC BGP Neighbor status="Up" hostname="%+{hostname}" store="%+{storenumber}" tunnel="%+{tunnel}" downtime="%TT" ECRule="01-bgp-flap-detection" ECRulenum="2"%{.nl} \ ) In this rule, the following 'lcall' action first verifies that we are dealing with tunnel 241 that has been down for more than 14400 seconds, and sets %o action list variable to either true or false: lcall %o %TT %+{tunnel} -> ( sub { $_[0] > 14400 && $_[1] eq "241" } ) After that, the if-else action executes different actions depending on the truth value of %o variable -- if %o is true, an event is written to standard output, otherwise a message is sent to port 514/tcp of host 10.3.0.85. If you want to execute tcpsock action for all events (be it tunnel 241 with long downtime or not), you can easily move 'tcpsock' action out from the else-block and drop the empty else-block of 'if' action altogether. However, if you would like to have several rules in place, you could generate a synthetic event from the Pair rule, and process this event by additional Single rule which checks the tunnel name and downtime. For example, consider the following ruleset of two rules: type=Pair ptype=PerlFunc pattern=sub { my(%var); \ if ($_[0] !~ /neighbor \*?(\d+\.\d+\.\d+\.\d+) Down/) { return 0; } \ $var{"nip"} = $1; $var{"ts"} = time(); \ $var{"hostname"} = scalar gethostbyaddr(Socket::inet_aton($var{"nip"}), Socket::AF_INET); \ if (!defined($var{"hostname"})) { $var{"hostname"} = $var{"nip"} }; \ $var{"storenumber"} = "NA"; $var{"tunnel"} = "NA"; \ if ($var{"hostname"} =~ /(\d+)lo/) { $var{"storenumber"} = $1; } \ if ($var{"hostname"} =~ /lo(\d+)/) { $var{"tunnel"} = $1; } \ return \%var; } desc=BGP Neighbor $+{nip} Down action=tcpsock 10.3.0.85:514<http://10.3.0.85:514> LzEC BGP Neighbor status="Down" hostname="$+{hostname}" store="$+{storenumber}" tunnel="$+{tunnel}" ECRule="01-bgp-flap-detection" ECRulenum="1"%{.nl}; ptype2=RegExp pattern2=neighbor \*?$+{nip} Up desc2=BGP Neighbor %+{nip} Up action2=lcall %TT %+{ts} -> ( sub { time() - $_[0] } ); \ tcpsock 10.3.0.85:514<http://10.3.0.85:514> LzEC BGP Neighbor status="Up" hostname="%+{hostname}" store="%+{storenumber}" tunnel="%+{tunnel}" downtime="%TT" ECRule="01-bgp-flap-detection" ECRulenum="2"%{.nl}; \ event LzEC BGP Neighbor status="Up" hostname="%+{hostname}" store="%+{storenumber}" tunnel="%+{tunnel}" downtime="%TT" ECRule="01-bgp-flap-detection" ECRulenum="2" type=Single ptype=PerlFunc pattern=sub { if ($_[0] !~ /LzEC BGP Neighbor status="Up" hostname="(\S+)" store="(\S+)" tunnel="241" downtime="(\d+)" ECRule="01-bgp-flap-detection" ECRulenum="2"/) { return 0; } \ if ($3 <= 14400) { return 0; } \ return ($1, $2, $3); } desc=event for tunnel 241 with long downtime action=write - Event for hostname $1 store $2 tunnel 241 downtime $3 The above ruleset use the approach you mentioned in your letter -- the tunnel name and downtime are checked within the PerlFunc pattern, and if tunnel 241 with long downtime is detected, the pattern matches. Finally, there is also another slightly less efficient way for writing the above Single rule which uses a RegExp pattern: type=Single ptype=RegExp pattern=LzEC BGP Neighbor status="Up" hostname="(\S+)" store="(\S+)" tunnel="241" downtime="(\d+)" ECRule="01-bgp-flap-detection" ECRulenum="2" context=$3 -> ( sub { $_[0] > 14400 } ) desc=event for tunnel 241 with long downtime action=write - Event for hostname $1 store $2 tunnel 241 downtime $3 This rule first matches the synthetic event with a traditional regular expression, and then executes a context expression that checks whether downtime is greater than 14400. Although this rule is computationally slightly more expensive (in addition to pattern matching there is also context evaluation), the Perl code in this rule is simpler and perhaps easier to read. Hopefully above examples provided some insights how you can potentially address the task that you have. kind regards, risto
_______________________________________________ Simple-evcorr-users mailing list Simple-evcorr-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/simple-evcorr-users