From c2eb12033b1c474952a55876dd7194d37ab96e3a Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Tue, 1 Nov 2022 15:18:49 +0000 Subject: [PATCH] 2022.11.01-15:18 2022.11.01-22:36 2022.11.01-22:56 2022.11.01-23:02 2022.11.01-23:06 2022.11.01-23:09 2022.11.01-23:13 2022.11.01-23:14 2022.11.01-23:16 2022.11.01-23:19 2022.11.01-23:22 2022.11.04-00:24 2022.11.04-01:12 2022.11.04-01:12 2022.11.04-01:13 2022.11.04-02:40 2022.11.04-06:58 2022.11.04-07:02 2022.11.08-09:15 2022.11.09-00:20 go mod 2022.11.09-00:21 2022.11.09-00:22 2022.11.09-00:32 2022.11.09-00:35 2022.11.09-00:42 2022.11.09-08:53 2022.11.09-09:01 2022.11.09-10:00 2022.11.11-13:46 2022.11.11-13:50 2022.11.11-14:09 2022.11.10-22:35 2022.11.10-23:32 performance log DEV 2022.11.11-13:43 2022.11.11-13:58 2022.11.11-14:11 2022.11.11-23:22 --- examples/agent_output_hook/config.yaml | 36 ++++---- misc/figures/n_flow_performance.png | Bin 0 -> 44969 bytes misc/figures/n_flow_performance.py | 35 ++++++++ misc/figures/n_hook_performance.png | Bin 0 -> 26856 bytes misc/figures/n_hook_performance.py | 23 ++++++ misc/figures/optimization.png | Bin 0 -> 19886 bytes misc/figures/optimization.py | 21 +++++ pkg/ebpfmap/types.go | 32 ------- pkg/flowctl/ipfix.go | 110 +++++++++++++++++++------ pkg/hook/command.go | 6 +- pkg/hook/interface.go | 2 +- pkg/hook/shell.go | 6 +- pkg/ipfix/config.go | 6 +- test.sh | 41 +++++++++ 14 files changed, 233 insertions(+), 85 deletions(-) create mode 100644 misc/figures/n_flow_performance.png create mode 100755 misc/figures/n_flow_performance.py create mode 100644 misc/figures/n_hook_performance.png create mode 100755 misc/figures/n_hook_performance.py create mode 100644 misc/figures/optimization.png create mode 100755 misc/figures/optimization.py create mode 100644 test.sh diff --git a/examples/agent_output_hook/config.yaml b/examples/agent_output_hook/config.yaml index e0bca76..329f48d 100644 --- a/examples/agent_output_hook/config.yaml +++ b/examples/agent_output_hook/config.yaml @@ -1,23 +1,23 @@ maxIpfixMessageLen: 100 -timerFinishedDrainSeconds: 1 -timerForceDrainSeconds: 30 -timerTemplateFlushSeconds: 60 +timerFinishedDrainSeconds: 10000 +timerForceDrainSeconds: 10 +timerTemplateFlushSeconds: 100000 outputs: - log: file: /tmp/flowlog.json hooks: - - name: hostname addition - command: ./misc/hook_command_example_dummy.sh - - name: shell to resolve hostname - shell: | - #!/bin/sh - echo `cat` | jq --arg hostname $(hostname) '. + {hostname: $hostname}' - - name: shell to resolve ifname from ifindex - shell: | - #!/bin/sh - IN=$(cat) - I_IDX=$(echo $IN | jq .ingressIfindex -r) - E_IDX=$(echo $IN | jq .egressIfindex -r ) - I_NAME=$(ip -n ns0 -j link | jq --argjson idx $I_IDX '.[] | select(.ifindex == $idx) | .ifname' -r) - E_NAME=$(ip -n ns0 -j link | jq --argjson idx $E_IDX '.[] | select(.ifindex == $idx) | .ifname' -r) - echo $IN | jq --arg i_name $I_NAME --arg e_name $E_NAME '. + {ingressIfname: $i_name, egressIfname: $e_name}' + # - command: /var/run/flowctl/hookbatch_all1.sh + - command: /var/run/flowctl/hookbatch_all2.sh + # - shell: | + # #!/bin/sh + # jq '[.[] | . + {foo1:"foo1"}]' \ + # | jq '[.[] | . + {foo2:"foo2"}]' \ + # | jq '[.[] | . + {foo3:"foo3"}]' \ + # | jq '[.[] | . + {foo4:"foo4"}]' \ + # | jq '[.[] | . + {foo5:"foo5"}]' \ + # | jq '[.[] | . + {foo6:"foo6"}]' \ + # | jq '[.[] | . + {foo7:"foo7"}]' \ + # | jq '[.[] | . + {foo8:"foo8"}]' + # - shell: | + # #!/bin/sh + # jq '[.[] | . + {foo1:"foo1",foo2:"foo2",foo3:"foo3",foo4:"foo4",foo5:"foo5",foo6:"foo6",foo7:"foo7",foo8:"foo8"}]' diff --git a/misc/figures/n_flow_performance.png b/misc/figures/n_flow_performance.png new file mode 100644 index 0000000000000000000000000000000000000000..ce159b0e04ce50615112250b8e9b43b9f33a4a1d GIT binary patch literal 44969 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 SQQZ~%Z=%tZvF8n~H~%liCqnZ8 literal 0 HcmV?d00001 diff --git a/misc/figures/n_flow_performance.py b/misc/figures/n_flow_performance.py new file mode 100755 index 0000000..8ff77fc --- /dev/null +++ b/misc/figures/n_flow_performance.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +import numpy as np +import matplotlib.pyplot as plt + +labels = ['34', '66', '130', '258'] +nobatch_many_jq = [2087720, 4070806, 7964851, 15761758] +nobatch_one_jq = [1075662, 2096756, 4110590, 8167249] +batch_many_jq = [(69832+74551+70318)/3, + (75263+78929+78031)/3, + (99978+96594+95671)/3, + (130711+127055+129459)/3] +batch_one_jq = [(36970+38420+34403)/3, + (40202+39713+39580)/3, + (44911+45686+47030)/3, + (52168+56735+51616)/3] + +x = np.arange(len(labels)) +width = 0.2 +fig, ax = plt.subplots() +rects1 = ax.bar(x - 1.5*width/1, nobatch_many_jq, width, label='nobatch-1shell-8jq') +rects2 = ax.bar(x - width/2, nobatch_one_jq, width, label='nobatch-1shell-1jq') +rects3 = ax.bar(x + width/2, batch_many_jq, width, label='batch-1shell-8jq') +rects4 = ax.bar(x + 1.5*width/1, batch_one_jq, width, label='batch-1shell-1jq') + +ax.set_ylabel('latency [usec]') +ax.set_xticks(x, labels) +ax.set_title('#Flows Performance') +ax.legend() + +ax.bar_label(rects1, padding=3) +ax.bar_label(rects2, padding=3) +ax.bar_label(rects3, padding=3) +ax.bar_label(rects4, padding=3) +fig.tight_layout() +plt.savefig("n_flow_performance.png") diff --git a/misc/figures/n_hook_performance.png b/misc/figures/n_hook_performance.png new file mode 100644 index 0000000000000000000000000000000000000000..7cda344ef52e1b2d09142ac6e68247ff39888473 GIT binary patch literal 26856 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

4`aCE`j-OAvo2(OAI4%^d{QiO*aa1yV> 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 0 { + slog.Info("drain finished flows", "usec", + time.Since(before).Microseconds(), "nFlows", nFlows) + } if err := ebpfmap.DeleteFinished(); err != nil { return err } case <-ticketForce.C: - slog.Info("force drain current flows") ebpfFlows, err := ebpfmap.Dump() if err != nil { return err @@ -293,12 +303,17 @@ func threadFlowExporter() error { if len(ebpfFlows) == 0 { continue } - if err := flushCaches(config); err != nil { + + before := time.Now() + nFlows, err := flushCaches(config) + if err != nil { return err } if err := ebpfmap.DeleteAll(); err != nil { return err } + slog.Info("force drain current flows", "usec", + time.Since(before).Microseconds(), "nFlows", nFlows) case <-tickerForTemplateFlush.C: slog.Info("flush ipfix template") buf1 := bytes.Buffer{} @@ -328,10 +343,10 @@ func threadFlowExporter() error { } } -func flushCachesFinished(config ipfix.Config) error { +func flushCachesFinished(config ipfix.Config) (int, error) { ebpfFlows0, err := ebpfmap.Dump() if err != nil { - return err + return 0, err } ebpfFlows := []ebpfmap.Flow{} for _, ebpfFlow := range ebpfFlows0 { @@ -342,80 +357,81 @@ func flushCachesFinished(config ipfix.Config) error { for _, o := range config.Outputs { if !o.Valid() { - return fmt.Errorf("invalid config") + return 0, fmt.Errorf("invalid config") } if o.Log != nil { if err := FlowOutputLog(ebpfFlows, o.Log.File, *o.Log); err != nil { - return err + return 0, err } } if o.Collector != nil { flow, err := ebpfmap.ToIpfixFlowFile(ebpfFlows) if err != nil { - return err + return 0, err } flowDataMessages, err := flow.ToFlowDataMessages(&config, 0) if err != nil { - return err + return 0, err } for _, flowDataMessage := range flowDataMessages { flowDataMessage.Header.SysupTime = uint32(util.TimeNow()) buf2 := bytes.Buffer{} if err := flowDataMessage.Write(&buf2, &config); err != nil { - return err + return 0, err } if err := util.UdpTransmit(o.Collector.LocalAddress, o.Collector.RemoteAddress, &buf2); err != nil { - return err + return 0, err } } } } - return nil + return len(ebpfFlows), err } -func flushCaches(config ipfix.Config) error { +func flushCaches(config ipfix.Config) (int, error) { ebpfFlows, err := ebpfmap.Dump() + nFlows := len(ebpfFlows) if err != nil { - return err + return 0, err } for _, o := range config.Outputs { if !o.Valid() { - return fmt.Errorf("invalid config") + return 0, fmt.Errorf("invalid config") } if o.Log != nil { if err := FlowOutputLog(ebpfFlows, o.Log.File, *o.Log); err != nil { - return err + return 0, err } } if o.Collector != nil { flow, err := ebpfmap.ToIpfixFlowFile(ebpfFlows) if err != nil { - return err + return 0, err } flowDataMessages, err := flow.ToFlowDataMessages(&config, 0) if err != nil { - return err + return 0, err } for _, flowDataMessage := range flowDataMessages { flowDataMessage.Header.SysupTime = uint32(util.TimeNow()) buf2 := bytes.Buffer{} if err := flowDataMessage.Write(&buf2, &config); err != nil { - return err + return 0, err } if err := util.UdpTransmit(o.Collector.LocalAddress, o.Collector.RemoteAddress, &buf2); err != nil { - return err + return 0, err } } } } - return nil + return nFlows, nil } -func FlowOutputLog(flows []ebpfmap.Flow, out string, o ipfix.OutputLog) error { +func getlogger(out string) logr.Logger { cfg := zap.NewProductionConfig() cfg.OutputPaths = []string{ out, @@ -425,13 +441,53 @@ func FlowOutputLog(flows []ebpfmap.Flow, out string, o ipfix.OutputLog) error { panic(fmt.Sprintf("who watches the watchmen (%v)?", err)) } log := zapr.NewLogger(zapLog) + return log + +} - for _, flow := range flows { - args, err := flow.ToZap(o) +func ebpflowsToMapArray(flows []ebpfmap.Flow) []map[string]interface{} { + flowTmp := []map[string]interface{}{} + for _, f := range flows { + flowTmp = append(flowTmp, map[string]interface{}{ + "src": util.ConvertUint32ToIP(f.Key.Saddr).String(), + "dst": util.ConvertUint32ToIP(f.Key.Daddr).String(), + "proto": f.Key.Proto, + "sport": f.Key.Sport, + "dport": f.Key.Dport, + "ingressIfindex": f.Key.IngressIfindex, + "egressIfindex": f.Key.EgressIfindex, + "pkts": f.Val.FlowPkts, + "bytes": f.Val.FlowBytes, + "action": f.Key.Mark, + "start": f.Val.FlowStartMilliSecond, + "end": f.Val.FlowEndMilliSecond, + "finished": f.Val.Finished, + }) + } + return flowTmp +} + +func tozap(m map[string]interface{}) []interface{} { + ret := []interface{}{} + for key, val := range m { + ret = append(ret, key, val) + } + return ret +} + +func FlowOutputLog(flows []ebpfmap.Flow, out string, o ipfix.OutputLog) error { + flowTmp := ebpflowsToMapArray(flows) + for _, h := range o.Hooks { + var err error + flowTmp, err = h.ExecuteBatch(flowTmp) if err != nil { return err } - log.Info("flowlog", args...) + } + + log := getlogger(out) + for _, flow := range flowTmp { + log.Info("flowlog", tozap(flow)...) } return nil } diff --git a/pkg/hook/command.go b/pkg/hook/command.go index 0bab052..af0e8c5 100644 --- a/pkg/hook/command.go +++ b/pkg/hook/command.go @@ -28,7 +28,9 @@ type Command string var _ Hook = (*Command)(nil) -func (c Command) Execute(in map[string]interface{}) (map[string]interface{}, error) { +func (c Command) ExecuteBatch(in []map[string]interface{}) ( + []map[string]interface{}, error) { + // Prepare input/output stdoutbuf := bytes.Buffer{} stderrbuf := bytes.Buffer{} @@ -48,7 +50,7 @@ func (c Command) Execute(in map[string]interface{}) (map[string]interface{}, err } // Convert back to map data from json-bytes - out := map[string]interface{}{} + out := []map[string]interface{}{} if err := json.Unmarshal(stdoutbuf.Bytes(), &out); err != nil { return nil, err } diff --git a/pkg/hook/interface.go b/pkg/hook/interface.go index c721c66..2918e5a 100644 --- a/pkg/hook/interface.go +++ b/pkg/hook/interface.go @@ -18,5 +18,5 @@ limitations under the License. package hook type Hook interface { - Execute(in map[string]interface{}) (map[string]interface{}, error) + ExecuteBatch(in []map[string]interface{}) ([]map[string]interface{}, error) } diff --git a/pkg/hook/shell.go b/pkg/hook/shell.go index 779d71b..2e688fc 100644 --- a/pkg/hook/shell.go +++ b/pkg/hook/shell.go @@ -30,7 +30,9 @@ type Shell string var _ Hook = (*Shell)(nil) -func (s Shell) Execute(in map[string]interface{}) (map[string]interface{}, error) { +func (s Shell) ExecuteBatch(in []map[string]interface{}) ( + []map[string]interface{}, error) { + // Create temp file from hook shell script hash := sha1.New() hash.Write([]byte(s)) @@ -58,7 +60,7 @@ func (s Shell) Execute(in map[string]interface{}) (map[string]interface{}, error } // Convert back to map data from json-bytes - out := map[string]interface{}{} + out := []map[string]interface{}{} if err := json.Unmarshal(stdoutbuf.Bytes(), &out); err != nil { return nil, err } diff --git a/pkg/ipfix/config.go b/pkg/ipfix/config.go index 60e2e30..b012206 100644 --- a/pkg/ipfix/config.go +++ b/pkg/ipfix/config.go @@ -81,15 +81,15 @@ func (h Hook) Valid() bool { return cnt == 1 } -func (h Hook) Execute(m map[string]interface{}) (map[string]interface{}, error) { +func (h Hook) ExecuteBatch(m []map[string]interface{}) ([]map[string]interface{}, error) { if !h.Valid() { return nil, fmt.Errorf("invalid hook") } if h.Shell != nil { - return h.Shell.Execute(m) + return h.Shell.ExecuteBatch(m) } if h.Command != nil { - return h.Command.Execute(m) + return h.Command.ExecuteBatch(m) } return nil, fmt.Errorf("(no reach code)") } diff --git a/test.sh b/test.sh new file mode 100644 index 0000000..b39998c --- /dev/null +++ b/test.sh @@ -0,0 +1,41 @@ +#!/bin/sh +mkdir -p /var/run/flowctl +echo "#!/bin/sh\njq '. + {foo1: \"foo1\"}'" > /var/run/flowctl/hook1.sh +echo "#!/bin/sh\njq '. + {foo2: \"foo2\"}'" > /var/run/flowctl/hook2.sh +echo "#!/bin/sh\njq '. + {foo3: \"foo3\"}'" > /var/run/flowctl/hook3.sh +echo "#!/bin/sh\njq '. + {foo4: \"foo4\"}'" > /var/run/flowctl/hook4.sh +echo "#!/bin/sh\njq '. + {foo5: \"foo5\"}'" > /var/run/flowctl/hook5.sh +echo "#!/bin/sh\njq '. + {foo6: \"foo6\"}'" > /var/run/flowctl/hook6.sh +echo "#!/bin/sh\njq '. + {foo7: \"foo7\"}'" > /var/run/flowctl/hook7.sh +echo "#!/bin/sh\njq '. + {foo8: \"foo8\"}'" > /var/run/flowctl/hook8.sh +cat < /var/run/flowctl/hook_all1.sh +#!/bin/sh +jq '. + {foo1: "foo1"}' \ + | jq '. + {foo2: "foo2"}' \ + | jq '. + {foo3: "foo3"}' \ + | jq '. + {foo4: "foo4"}' \ + | jq '. + {foo5: "foo5"}' \ + | jq '. + {foo6: "foo6"}' \ + | jq '. + {foo7: "foo7"}' \ + | jq '. + {foo8: "foo8"}' +EOF +cat < /var/run/flowctl/hook_all2.sh +#!/bin/sh +jq '.+{foo1:"foo1",foo2:"foo2",foo3:"foo3",foo4:"foo4",foo5:"foo5",foo6:"foo6",foo7:"foo7",foo8:"foo8"}' +EOF +cat < /var/run/flowctl/hookbatch_all1.sh +#!/bin/sh +jq '[.[] | . + {foo1:"foo1"}]' \\ + | jq '[.[] | . + {foo2:"foo2"}]' \\ + | jq '[.[] | . + {foo3:"foo3"}]' \\ + | jq '[.[] | . + {foo4:"foo4"}]' \\ + | jq '[.[] | . + {foo5:"foo5"}]' \\ + | jq '[.[] | . + {foo6:"foo6"}]' \\ + | jq '[.[] | . + {foo7:"foo7"}]' \\ + | jq '[.[] | . + {foo8:"foo8"}]' +EOF +cat < /var/run/flowctl/hookbatch_all2.sh +#!/bin/sh +jq '[.[] | . + {foo1:"foo1",foo2:"foo2",foo3:"foo3",foo4:"foo4",foo5:"foo5",foo6:"foo6",foo7:"foo7",foo8:"foo8"}]' +EOF +chmod +x /var/run/flowctl/hook*.sh