From ebd672b13647d8e54cf398c429a668f97a0f79ed Mon Sep 17 00:00:00 2001 From: Antonin Bas Date: Fri, 27 Oct 2023 19:52:45 -0700 Subject: [PATCH] Replace contiv/libovsdb with ovn-org/libovsdb contiv/libovsdb is abandoned and we were using a version from 2017 Instead we use github.com/ovn-org/libovsdb, which is still under active development and is used by ovn-kubernetes. We also move the ovsdbDriver code to an internal package: it is only used for integration tests and does not need to be part of the public API. All the functions that were not used anywhere are also removed. Bump up version to v0.13.0. Fixes #62 Signed-off-by: Antonin Bas --- VERSION | 2 +- go.mod | 21 +- go.sum | 478 ++++++++++++++++- ofctrl/internal/ovsdbDriver.go | 200 +++++++ ofctrl/internal/vswitchd/bridge.go | 31 ++ ofctrl/internal/vswitchd/model.go | 12 + ofctrl/internal/vswitchd/open_vswitch.go | 8 + ofctrl/multipart_test.go | 2 +- ofctrl/ofctrl_test.go | 176 +++---- ofctrl/ofpacket_test.go | 4 +- ofctrl/ovsdbDriver.go | 637 ----------------------- 11 files changed, 831 insertions(+), 740 deletions(-) create mode 100644 ofctrl/internal/ovsdbDriver.go create mode 100644 ofctrl/internal/vswitchd/bridge.go create mode 100644 ofctrl/internal/vswitchd/model.go create mode 100644 ofctrl/internal/vswitchd/open_vswitch.go delete mode 100644 ofctrl/ovsdbDriver.go diff --git a/VERSION b/VERSION index 87a1cf59..6345c216 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v0.12.0 +v0.13.0 diff --git a/go.mod b/go.mod index 5f1d63a6..9559f522 100644 --- a/go.mod +++ b/go.mod @@ -5,23 +5,34 @@ go 1.21 require ( antrea.io/libOpenflow v0.13.0 github.com/Microsoft/go-winio v0.6.1 - github.com/contiv/libovsdb v0.0.0-20170227191248-d0061a53e358 github.com/orcaman/concurrent-map/v2 v2.0.1 + github.com/ovn-org/libovsdb v0.6.1-0.20230912124059-239822fe891a github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.8.4 ) require ( - github.com/cenkalti/hub v1.0.1-0.20140529221144-7be60e186e66 // indirect - github.com/cenkalti/rpc2 v0.0.0-20140912135055-44d0d95e4f52 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cenkalti/backoff/v4 v4.1.3 // indirect + github.com/cenkalti/hub v1.0.1 // indirect + github.com/cenkalti/rpc2 v0.0.0-20210604223624-c1acbc6ec984 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-logr/logr v1.2.0 // indirect + github.com/go-logr/logr v1.2.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/uuid v1.2.0 // indirect github.com/kr/pretty v0.2.0 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_golang v1.12.1 // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.32.1 // indirect + github.com/prometheus/procfs v0.7.3 // indirect golang.org/x/mod v0.8.0 // indirect golang.org/x/sys v0.5.0 // indirect golang.org/x/tools v0.6.0 // indirect - gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect + google.golang.org/protobuf v1.28.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.100.1 // indirect ) diff --git a/go.sum b/go.sum index aabb9a31..e942fda7 100644 --- a/go.sum +++ b/go.sum @@ -1,47 +1,511 @@ antrea.io/libOpenflow v0.13.0 h1:CelrRAMUk2wZyLI7KrYy2+cbFsJrWVIQp3xlP/pnNu4= antrea.io/libOpenflow v0.13.0/go.mod h1:U8YR0ithWrjwLdUUhyeCsYnlKg/mEFjG5CbPNt1V+j0= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/cenkalti/hub v1.0.1-0.20140529221144-7be60e186e66 h1:mqwgWF7yBJ/zOFlWZk84IRFG/FhMG0f7aZWvcTx/JHA= -github.com/cenkalti/hub v1.0.1-0.20140529221144-7be60e186e66/go.mod h1:tcYwtS3a2d9NO/0xDXVJWx3IedurUjYCqFCmpi0lpHs= -github.com/cenkalti/rpc2 v0.0.0-20140912135055-44d0d95e4f52 h1:LnaEnQZECBs+zizOdhjYpYAfshAmeQa3556LlhONGUs= -github.com/cenkalti/rpc2 v0.0.0-20140912135055-44d0d95e4f52/go.mod h1:v2npkhrXyk5BCnkNIiPdRI23Uq6uWPUQGL2hnRcRr/M= -github.com/contiv/libovsdb v0.0.0-20170227191248-d0061a53e358 h1:AiA9SKyNXulsU7aAnyka3UFHYOIH00A9HvdIRnDXlg0= -github.com/contiv/libovsdb v0.0.0-20170227191248-d0061a53e358/go.mod h1:+qKEHaNVPj+wrn5st7TEFH9wcUWCJq5ZBvVKPQwzAeg= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cenk/hub v1.0.1 h1:RBwXNOF4a8KjD8BJ08XqN8KbrqaGiQLDrgvUGJSHuPA= +github.com/cenk/hub v1.0.1/go.mod h1:rJM1LNAW0ppT8FMMuPK6c2NP/R2nH/UthtuRySSaf6Y= +github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= +github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/hub v1.0.1 h1:UMtjc6dHSaOQTO15SVA50MBIR9zQwvsukQupDrkIRtg= +github.com/cenkalti/hub v1.0.1/go.mod h1:tcYwtS3a2d9NO/0xDXVJWx3IedurUjYCqFCmpi0lpHs= +github.com/cenkalti/rpc2 v0.0.0-20210604223624-c1acbc6ec984 h1:CNwZyGS6KpfaOWbh2yLkSy3rSTUh3jub9CzpFpP6PVQ= +github.com/cenkalti/rpc2 v0.0.0-20210604223624-c1acbc6ec984/go.mod h1:v2npkhrXyk5BCnkNIiPdRI23Uq6uWPUQGL2hnRcRr/M= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/orcaman/concurrent-map/v2 v2.0.1 h1:jOJ5Pg2w1oeB6PeDurIYf6k9PQ+aTITr/6lP/L/zp6c= github.com/orcaman/concurrent-map/v2 v2.0.1/go.mod h1:9Eq3TG2oBe5FirmYWQfYO5iH1q0Jv47PLaNK++uCdOM= +github.com/ovn-org/libovsdb v0.6.1-0.20230912124059-239822fe891a h1:6bv0BvHLB4Ustw/rwk2ErCuldlS9gFiuwgPvFVEdvQg= +github.com/ovn-org/libovsdb v0.6.1-0.20230912124059-239822fe891a/go.mod h1:LC5DOvcY58jOG3HTvDyCVidoMJDurPeu+xlxv5Krd9Q= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/ofctrl/internal/ovsdbDriver.go b/ofctrl/internal/ovsdbDriver.go new file mode 100644 index 00000000..927dd9f0 --- /dev/null +++ b/ofctrl/internal/ovsdbDriver.go @@ -0,0 +1,200 @@ +package internal + +import ( + "context" + "fmt" + + "github.com/ovn-org/libovsdb/client" + "github.com/ovn-org/libovsdb/model" + "github.com/ovn-org/libovsdb/ovsdb" + log "github.com/sirupsen/logrus" + + "antrea.io/ofnet/ofctrl/internal/vswitchd" +) + +// OVS driver state +type OvsDriver struct { + // OVS client + client client.Client + + // Name of the OVS bridge + brName string + + rootUUID string +} + +func newOvsDriver(ctx context.Context, bridgeName string) (*OvsDriver, error) { + dbModel, err := vswitchd.Model() + if err != nil { + return nil, err + } + ovs, err := client.NewOVSDBClient(dbModel, client.WithEndpoint("tcp:localhost:6640")) + if err != nil { + return nil, fmt.Errorf("failed to create client: %w", err) + } + if err := ovs.Connect(ctx); err != nil { + return nil, fmt.Errorf("failed to connect to ovsdb: %w", err) + } + + if _, err := ovs.Monitor( + ctx, + ovs.NewMonitor( + client.WithTable(&vswitchd.OpenvSwitch{}), + client.WithTable(&vswitchd.Bridge{}), + ), + ); err != nil { + return nil, err + } + + // Get root UUID + var rootUUID string + for uuid := range ovs.Cache().Table("Open_vSwitch").Rows() { + rootUUID = uuid + } + + ovsDriver := &OvsDriver{ + client: ovs, + brName: bridgeName, + rootUUID: rootUUID, + } + if err := ovsDriver.createBridge(ctx); err != nil { + return nil, fmt.Errorf("failed to create bridge: %w", err) + } + return ovsDriver, nil +} + +// Create a new OVS driver +func NewOvsDriver(bridgeName string) *OvsDriver { + ovsDriver, err := newOvsDriver(context.Background(), bridgeName) + if err != nil { + log.Fatalf("fail to create OVS driver: %v", err) + } + return ovsDriver +} + +// Delete removes the bridge and disconnects the client +func (d *OvsDriver) Delete() error { + if d.client != nil { + if err := d.deleteBridge(context.Background()); err != nil { + return fmt.Errorf("error when deleting bridge %s: %w", d.brName, err) + } + log.Infof("Deleting OVS bridge: %s", d.brName) + d.client.Disconnect() + } + + return nil +} + +// Wrapper for ovsDB transaction +func (d *OvsDriver) ovsdbTransact(ctx context.Context, ops []ovsdb.Operation) error { + // Print out what we are sending + log.Debugf("Transaction: %+v\n", ops) + + // Perform OVSDB transaction + reply, err := d.client.Transact(ctx, ops...) + if err != nil { + return err + } + + if _, err := ovsdb.CheckOperationResults(reply, ops); err != nil { + return err + } + + return nil +} + +func (d *OvsDriver) createBridge(ctx context.Context) error { + // If the bridge already exists, just return + // FIXME: should we delete the old bridge and create new one? + if _, ok := d.getBridgeUUID(); ok { + return nil + } + + const brNamedUUID = "testbr" + + protocols := []vswitchd.BridgeProtocols{ + vswitchd.BridgeProtocolsOpenflow10, + vswitchd.BridgeProtocolsOpenflow11, + vswitchd.BridgeProtocolsOpenflow12, + vswitchd.BridgeProtocolsOpenflow13, + vswitchd.BridgeProtocolsOpenflow14, + vswitchd.BridgeProtocolsOpenflow15, + } + br := &vswitchd.Bridge{ + UUID: brNamedUUID, + FailMode: &vswitchd.BridgeFailModeSecure, + Name: d.brName, + Protocols: protocols, + } + + insertOps, err := d.client.Create(br) + if err != nil { + return err + } + + // Inserting/Deleting a Bridge row in Bridge table requires mutating + // the open_vswitch table. + ovsRow := vswitchd.OpenvSwitch{ + UUID: d.rootUUID, + } + mutateOps, err := d.client.Where(&ovsRow).Mutate(&ovsRow, model.Mutation{ + Field: &ovsRow.Bridges, + Mutator: "insert", + Value: []string{br.UUID}, + }) + if err != nil { + return err + } + + ops := append(insertOps, mutateOps...) + + return d.ovsdbTransact(ctx, ops) +} + +func (d *OvsDriver) deleteBridge(ctx context.Context) error { + uuid, ok := d.getBridgeUUID() + if !ok { + return nil + } + br := &vswitchd.Bridge{ + UUID: uuid, + } + + deleteOps, err := d.client.Where(br).Delete() + if err != nil { + return err + } + + // Inserting/Deleting a Bridge row in Bridge table requires mutating + // the open_vswitch table. + ovsRow := vswitchd.OpenvSwitch{ + UUID: d.rootUUID, + } + mutateOps, err := d.client.Where(&ovsRow).Mutate(&ovsRow, model.Mutation{ + Field: &ovsRow.Bridges, + Mutator: "delete", + Value: []string{br.UUID}, + }) + if err != nil { + return err + } + + ops := append(deleteOps, mutateOps...) + + return d.ovsdbTransact(ctx, ops) +} + +func (d *OvsDriver) getBridgeUUID() (string, bool) { + rows := d.client.Cache().Table("Bridge").Rows() + for uuid, m := range rows { + br := m.(*vswitchd.Bridge) + if br.Name == d.brName { + return uuid, true + } + } + return "", false +} + +func (d *OvsDriver) BridgeName() string { + return d.brName +} diff --git a/ofctrl/internal/vswitchd/bridge.go b/ofctrl/internal/vswitchd/bridge.go new file mode 100644 index 00000000..9339f72a --- /dev/null +++ b/ofctrl/internal/vswitchd/bridge.go @@ -0,0 +1,31 @@ +package vswitchd + +type ( + BridgeFailMode = string + BridgeProtocols = string +) + +var ( + BridgeFailModeStandalone BridgeFailMode = "standalone" + BridgeFailModeSecure BridgeFailMode = "secure" + BridgeProtocolsOpenflow10 BridgeProtocols = "OpenFlow10" + BridgeProtocolsOpenflow11 BridgeProtocols = "OpenFlow11" + BridgeProtocolsOpenflow12 BridgeProtocols = "OpenFlow12" + BridgeProtocolsOpenflow13 BridgeProtocols = "OpenFlow13" + BridgeProtocolsOpenflow14 BridgeProtocols = "OpenFlow14" + BridgeProtocolsOpenflow15 BridgeProtocols = "OpenFlow15" +) + +// Bridge defines an object in Bridge table +// We only include the fields we need +type Bridge struct { + UUID string `ovsdb:"_uuid"` + // Include these fields (DatapathID, DatapathVersion) so that libovsdb + // does not complain about missing model fields. + DatapathID *string `ovsdb:"datapath_id"` + DatapathType string `ovsdb:"datapath_type"` + DatapathVersion string `ovsdb:"datapath_version"` + FailMode *BridgeFailMode `ovsdb:"fail_mode"` + Name string `ovsdb:"name"` + Protocols []BridgeProtocols `ovsdb:"protocols"` +} diff --git a/ofctrl/internal/vswitchd/model.go b/ofctrl/internal/vswitchd/model.go new file mode 100644 index 00000000..a2670dd2 --- /dev/null +++ b/ofctrl/internal/vswitchd/model.go @@ -0,0 +1,12 @@ +package vswitchd + +import ( + "github.com/ovn-org/libovsdb/model" +) + +func Model() (model.ClientDBModel, error) { + return model.NewClientDBModel("Open_vSwitch", map[string]model.Model{ + "Bridge": &Bridge{}, + "Open_vSwitch": &OpenvSwitch{}, + }) +} diff --git a/ofctrl/internal/vswitchd/open_vswitch.go b/ofctrl/internal/vswitchd/open_vswitch.go new file mode 100644 index 00000000..64bc8bf3 --- /dev/null +++ b/ofctrl/internal/vswitchd/open_vswitch.go @@ -0,0 +1,8 @@ +package vswitchd + +// OpenvSwitch defines an object in Open_vSwitch table +// We only include the fields we need +type OpenvSwitch struct { + UUID string `ovsdb:"_uuid"` + Bridges []string `ovsdb:"bridges"` +} diff --git a/ofctrl/multipart_test.go b/ofctrl/multipart_test.go index 5cd8a18b..3bf65b98 100644 --- a/ofctrl/multipart_test.go +++ b/ofctrl/multipart_test.go @@ -27,7 +27,7 @@ func TestMultipartReply(t *testing.T) { brName := "brMultipart" ovsBr := prepareControllerAndSwitch(t, app.OfActor, ctrl, brName) defer func() { - assert.Nilf(t, ovsBr.DeleteBridge(brName), "Failed to delete br %s", brName) + assert.NoError(t, ovsBr.Delete()) ctrl.Delete() }() testTableFeatures(t, app) diff --git a/ofctrl/ofctrl_test.go b/ofctrl/ofctrl_test.go index e0c5fe07..320acba6 100644 --- a/ofctrl/ofctrl_test.go +++ b/ofctrl/ofctrl_test.go @@ -28,6 +28,8 @@ import ( log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "antrea.io/ofnet/ofctrl/internal" ) type OfActor struct { @@ -84,7 +86,7 @@ func (o *OfActor) TLVMapEnabledOnSwitch() bool { // Controller/Application/ovsBr work on clientMode var ofActor *OfActor var ctrler *Controller -var ovsDriver *OvsDriver +var ovsDriver *internal.OvsDriver // Run an ovs-ofctl command func runOfctlCmd(cmd, brName string) ([]byte, error) { @@ -162,7 +164,7 @@ func TestMain(m *testing.M) { ctrler = NewController(ofActor) // Create ovs bridge and connect clientMode Controller to it - ovsDriver = NewOvsDriver("ovsbr12") + ovsDriver = internal.NewOvsDriver("ovsbr12") //wait for 2sec and see if ovs br created log.Infof("wait for 2sec for ovs bridge ovsbr12 to get created..") time.Sleep(2 * time.Second) @@ -194,7 +196,7 @@ func TestMain(m *testing.M) { exitCode := m.Run() // delete the bridge - err = ovsDriver.DeleteBridge(ovsDriver.OvsBridgeName) + err = ovsDriver.Delete() if err != nil { log.Fatalf("Error deleting the bridge: %v", err) } @@ -236,14 +238,14 @@ func TestPushMplsFlow(t *testing.T) { assert.NoError(t, err, "Error installing inport flow") // verify push mpls action exists - assert.True(t, ofctlDumpFlowMatch(ovsDriver.OvsBridgeName, 0, "priority=100,in_port=1", "push_mpls:0x8847,goto_table:1"), "in port flow not found in OVS.") + assert.True(t, ofctlDumpFlowMatch(ovsDriver.BridgeName(), 0, "priority=100,in_port=1", "push_mpls:0x8847,goto_table:1"), "in port flow not found in OVS.") // delete the flow err = inPortFlow.Delete() assert.NoError(t, err, "Error deleting the inPort flow") // Make sure they are really gone - assert.False(t, ofctlDumpFlowMatch(ovsDriver.OvsBridgeName, 0, "priority=100,in_port=1", "push_mpls:0x8847,goto_table:1"), "in port flow still found in OVS after deleting it.") + assert.False(t, ofctlDumpFlowMatch(ovsDriver.BridgeName(), 0, "priority=100,in_port=1", "push_mpls:0x8847,goto_table:1"), "in port flow still found in OVS after deleting it.") } func TestPopMplsFlow(t *testing.T) { @@ -259,14 +261,14 @@ func TestPopMplsFlow(t *testing.T) { assert.NoError(t, err, "Error installing inport flow") // verify pop mpls action exists - assert.True(t, ofctlDumpFlowMatch(ovsDriver.OvsBridgeName, 0, "priority=100,mpls", "pop_mpls:0x0800,goto_table:1"), "mpls flow not found in OVS.") + assert.True(t, ofctlDumpFlowMatch(ovsDriver.BridgeName(), 0, "priority=100,mpls", "pop_mpls:0x0800,goto_table:1"), "mpls flow not found in OVS.") // delete the flow err = mplsFlow.Delete() assert.NoError(t, err, "Error deleting the inPort flow") // Make sure they are really gone - assert.False(t, ofctlDumpFlowMatch(ovsDriver.OvsBridgeName, 0, "priority=100,mpls", "pop_mpls:0x0800,goto_table:1"), "mpls flow still found in OVS after deleting it.") + assert.False(t, ofctlDumpFlowMatch(ovsDriver.BridgeName(), 0, "priority=100,mpls", "pop_mpls:0x0800,goto_table:1"), "mpls flow still found in OVS after deleting it.") } func TestCreateDeleteFlow(t *testing.T) { @@ -327,7 +329,7 @@ func TestCreateDeleteFlow(t *testing.T) { assert.Nil(t, err, "Error installing the tcp flow") // verify it got installed - flowList, err := ofctlFlowDump(ovsDriver.OvsBridgeName) + flowList, err := ofctlFlowDump(ovsDriver.BridgeName()) assert.Nil(t, err, "Error getting flow entry") // Match inport flow @@ -363,7 +365,7 @@ func TestCreateDeleteFlow(t *testing.T) { assert.NoError(t, err, "Error deleting the tcp flow") // Make sure they are really gone - flowList, err = ofctlFlowDump(ovsDriver.OvsBridgeName) + flowList, err = ofctlFlowDump(ovsDriver.BridgeName()) assert.NoError(t, err, "Error getting flow entry") // Match inport flow and see if its still there.. @@ -402,14 +404,14 @@ func TestSetUnsetDscp(t *testing.T) { assert.NoError(t, err, "Error installing inport flow") // verify dscp action exists - assert.True(t, ofctlDumpFlowMatch(ovsDriver.OvsBridgeName, 0, "priority=100,ip,in_port=1,nw_tos=184", + assert.True(t, ofctlDumpFlowMatch(ovsDriver.BridgeName(), 0, "priority=100,ip,in_port=1,nw_tos=184", "set_field:23->ip_dscp,push_vlan:0x8100,set_field:4097->vlan_vid,goto_table:1"), "in port flow not found in OVS.") // unset dscp inPortFlow.UnsetDscp() // verify dscp action is gone - assert.True(t, ofctlDumpFlowMatch(ovsDriver.OvsBridgeName, 0, "priority=100,ip,in_port=1,nw_tos=184", + assert.True(t, ofctlDumpFlowMatch(ovsDriver.BridgeName(), 0, "priority=100,ip,in_port=1,nw_tos=184", "push_vlan:0x8100,set_field:4097->vlan_vid,goto_table:1"), "in port flow not found in OVS.") // delete the flow @@ -417,7 +419,7 @@ func TestSetUnsetDscp(t *testing.T) { assert.NoError(t, err, "Error deleting the inPort flow") // Make sure they are really gone - assert.False(t, ofctlDumpFlowMatch(ovsDriver.OvsBridgeName, 0, "priority=100,in_port=1", + assert.False(t, ofctlDumpFlowMatch(ovsDriver.BridgeName(), 0, "priority=100,in_port=1", "push_vlan:0x8100,set_field:4097->vlan_vid,goto_table:1"), "in_port flow still found in OVS after deleting it.") } @@ -440,7 +442,7 @@ func TestMatchSetMetadata(t *testing.T) { assert.NoError(t, err, "Error installing inport flow") // verify metadata action exists - assert.True(t, ofctlDumpFlowMatch(ovsDriver.OvsBridgeName, 0, "priority=100,metadata=0x1100/0x1100,in_port=1", + assert.True(t, ofctlDumpFlowMatch(ovsDriver.BridgeName(), 0, "priority=100,metadata=0x1100/0x1100,in_port=1", "write_metadata:0x8800/0x8800,goto_table:1"), "in port flow not found in OVS.") // delete the flow @@ -448,7 +450,7 @@ func TestMatchSetMetadata(t *testing.T) { assert.NoError(t, err, "Error deleting the inPort flow") // Make sure they are really gone - assert.False(t, ofctlDumpFlowMatch(ovsDriver.OvsBridgeName, 0, "priority=100,metadata=0x1100/0x1100,in_port=1", + assert.False(t, ofctlDumpFlowMatch(ovsDriver.BridgeName(), 0, "priority=100,metadata=0x1100/0x1100,in_port=1", "write_metadata:0x8800/0x8800,goto_table:1"), "in port flow still found in OVS after deleting it.") } @@ -469,7 +471,7 @@ func TestMatchSetTunnelId(t *testing.T) { assert.NoError(t, err, "Error installing inport flow") // verify metadata action exists - assert.True(t, ofctlDumpFlowMatch(ovsDriver.OvsBridgeName, 0, "priority=100,tun_id=0xa,in_port=1", + assert.True(t, ofctlDumpFlowMatch(ovsDriver.BridgeName(), 0, "priority=100,tun_id=0xa,in_port=1", "set_field:0x14->tun_id,goto_table:1"), "in port flow not found in OVS.") // delete the flow @@ -477,7 +479,7 @@ func TestMatchSetTunnelId(t *testing.T) { assert.NoError(t, err, "Error deleting the inPort flow") // Make sure they are really gone - assert.False(t, ofctlDumpFlowMatch(ovsDriver.OvsBridgeName, 0, "priority=100,tun_id=0xa,in_port=1", + assert.False(t, ofctlDumpFlowMatch(ovsDriver.BridgeName(), 0, "priority=100,tun_id=0xa,in_port=1", "set_field:0x14->tun_id,goto_table:1"), "in port flow still found in OVS after deleting it.") } @@ -507,7 +509,7 @@ func TestMatchSetIpFields(t *testing.T) { assert.NoError(t, err, "Error installing inport flow") // verify metadata action exists - assert.True(t, ofctlDumpFlowMatch(ovsDriver.OvsBridgeName, 0, "priority=100,tcp,in_port=1,nw_src=10.1.1.0/24,nw_dst=10.2.1.0/24", + assert.True(t, ofctlDumpFlowMatch(ovsDriver.BridgeName(), 0, "priority=100,tcp,in_port=1,nw_src=10.1.1.0/24,nw_dst=10.2.1.0/24", "set_field:20.2.1.1->ip_dst,set_field:20.1.1.1->ip_src,goto_table:1"), "in port flow not found in OVS.") // delete the flow @@ -515,7 +517,7 @@ func TestMatchSetIpFields(t *testing.T) { assert.NoError(t, err, "Error deleting the inPort flow") // Make sure they are really gone - assert.False(t, ofctlDumpFlowMatch(ovsDriver.OvsBridgeName, 0, "priority=100,tcp,in_port=1,nw_src=10.1.1.0/24,nw_dst=10.2.1.0/24", + assert.False(t, ofctlDumpFlowMatch(ovsDriver.BridgeName(), 0, "priority=100,tcp,in_port=1,nw_src=10.1.1.0/24,nw_dst=10.2.1.0/24", "set_field:20.2.1.1->ip_dst,set_field:20.1.1.1->ip_src,goto_table:1"), "in port flow still found in OVS after deleting it.") } @@ -545,7 +547,7 @@ func TestMatchIpv6Fields(t *testing.T) { assert.NoError(t, err, "Error installing inport flow") // verify metadata action exists - assert.True(t, ofctlDumpFlowMatch(ovsDriver.OvsBridgeName, 0, "priority=100,tcp6,in_port=1,ipv6_src=2016:616::/100,ipv6_dst=2016:617::/100,nw_tos=92", + assert.True(t, ofctlDumpFlowMatch(ovsDriver.BridgeName(), 0, "priority=100,tcp6,in_port=1,ipv6_src=2016:616::/100,ipv6_dst=2016:617::/100,nw_tos=92", "set_field:46->ip_dscp,goto_table:1"), "in port flow not found in OVS.") // delete the flow @@ -553,7 +555,7 @@ func TestMatchIpv6Fields(t *testing.T) { assert.NoError(t, err, "Error deleting the inPort flow") // Make sure they are really gone - assert.False(t, ofctlDumpFlowMatch(ovsDriver.OvsBridgeName, 0, "priority=100,tcp6,in_port=1,ipv6_src=2016:616::/100,ipv6_dst=2016:617::/100,nw_tos=92", + assert.False(t, ofctlDumpFlowMatch(ovsDriver.BridgeName(), 0, "priority=100,tcp6,in_port=1,ipv6_src=2016:616::/100,ipv6_dst=2016:617::/100,nw_tos=92", "set_field:46->ip_dscp,goto_table:1"), "in port flow still found in OVS after deleting it.") } @@ -583,7 +585,7 @@ func TestMatchSetTcpFields(t *testing.T) { assert.NoError(t, err, "Error installing inport flow") // verify metadata action exists - assert.True(t, ofctlDumpFlowMatch(ovsDriver.OvsBridgeName, 0, "priority=100,tcp,in_port=1,tp_src=0x8000/0xfff8,tp_dst=9000,tcp_flags=+syn+ack", + assert.True(t, ofctlDumpFlowMatch(ovsDriver.BridgeName(), 0, "priority=100,tcp,in_port=1,tp_src=0x8000/0xfff8,tp_dst=9000,tcp_flags=+syn+ack", "set_field:5000->tcp_dst,set_field:4000->tcp_src,goto_table:1"), "in port flow not found in OVS.") // delete the flow @@ -591,7 +593,7 @@ func TestMatchSetTcpFields(t *testing.T) { assert.NoError(t, err, "Error deleting the inPort flow") // Make sure they are really gone - assert.False(t, ofctlDumpFlowMatch(ovsDriver.OvsBridgeName, 0, "priority=100,tcp,in_port=1,tp_src=0x8000/0xfff8,tp_dst=9000,tcp_flags=+syn+ack", + assert.False(t, ofctlDumpFlowMatch(ovsDriver.BridgeName(), 0, "priority=100,tcp,in_port=1,tp_src=0x8000/0xfff8,tp_dst=9000,tcp_flags=+syn+ack", "set_field:5000->tcp_dst,set_field:4000->tcp_src,goto_table:1"), "in port flow still found in OVS after deleting it.") } @@ -616,7 +618,7 @@ func TestMatchSetUdpFields(t *testing.T) { assert.NoError(t, err, "Error installing inport flow") // verify metadata action exists - assert.True(t, ofctlDumpFlowMatch(ovsDriver.OvsBridgeName, 0, "priority=100,udp,in_port=1,tp_src=8000,tp_dst=9000", + assert.True(t, ofctlDumpFlowMatch(ovsDriver.BridgeName(), 0, "priority=100,udp,in_port=1,tp_src=8000,tp_dst=9000", "set_field:5000->udp_dst,set_field:4000->udp_src,goto_table:1"), "in port flow not found in OVS.") // delete the flow @@ -624,7 +626,7 @@ func TestMatchSetUdpFields(t *testing.T) { assert.NoError(t, err, "Error deleting the inPort flow") // Make sure they are really gone - assert.False(t, ofctlDumpFlowMatch(ovsDriver.OvsBridgeName, 0, "priority=100,udp,in_port=1,tp_src=8000,tp_dst=9000", + assert.False(t, ofctlDumpFlowMatch(ovsDriver.BridgeName(), 0, "priority=100,udp,in_port=1,tp_src=8000,tp_dst=9000", "set_field:5000->udp_dst,set_field:4000->udp_src,goto_table:1"), "in port flow still found in OVS after deleting it.") } @@ -683,7 +685,7 @@ func TestOFSwitch_DumpFlowStats(t *testing.T) { } func TestMultiRangeOneReg(t *testing.T) { - brName := ovsDriver.OvsBridgeName + brName := ovsDriver.BridgeName() log.Infof("Enable monitor flows on table %d in bridge %s", ofActor.inputTable.TableId, brName) ofActor.Switch.EnableMonitor() @@ -790,20 +792,20 @@ func TestReconnectOFSwitch(t *testing.T) { defer func() { // Wait for flow entries flush time.Sleep(1 * time.Second) - err := ovsBr.DeleteBridge(brName) + err := ovsBr.Delete() assert.NoErrorf(t, err, "Failed to delete br %s", brName) ctrl.Delete() }() assert.Equal(t, app.connectedCount, 1) go func() { - ovsBr.DeleteBridge(brName) + ovsBr.Delete() select { case <-time.After(10 * time.Second): - ovsBr = NewOvsDriver(brName) + ovsBr = internal.NewOvsDriver(brName) } }() - ovsBr.DeleteBridge(brName) + ovsBr.Delete() select { case <-time.After(15 * time.Second): break @@ -811,9 +813,9 @@ func TestReconnectOFSwitch(t *testing.T) { assert.Equal(t, 2, app.connectedCount) } -func prepareControllerAndSwitch(t *testing.T, app *OfActor, ctrl *Controller, brName string) (ovsBr *OvsDriver) { +func prepareControllerAndSwitch(t *testing.T, app *OfActor, ctrl *Controller, brName string) (ovsBr *internal.OvsDriver) { // Create ovs bridge and connect clientMode Controller to it - ovsBr = NewOvsDriver(brName) + ovsBr = internal.NewOvsDriver(brName) go ctrl.Connect(fmt.Sprintf("/var/run/openvswitch/%s.mgmt", brName)) time.Sleep(2 * time.Second) @@ -831,7 +833,7 @@ func setOfTables(t *testing.T, ofActor2 *OfActor, brName string) { } func TestBundles(t *testing.T) { - brName := ovsDriver.OvsBridgeName + brName := ovsDriver.BridgeName() // Test transaction complete workflow tx := ofActor.Switch.NewTransaction(Atomic) err := tx.Begin() @@ -901,7 +903,7 @@ func TestBundles(t *testing.T) { } func TestBundle2(t *testing.T) { - brName := ovsDriver.OvsBridgeName + brName := ovsDriver.BridgeName() // Test transaction complete workflow tx := ofActor.Switch.NewTransaction(Ordered) err := tx.Begin() @@ -958,7 +960,7 @@ func TestBundle2(t *testing.T) { } func TestGroupWithSelectionMethod(t *testing.T) { - brName := ovsDriver.OvsBridgeName + brName := ovsDriver.BridgeName() tcpSrcPortFieldWithValue := openflow15.NewTcpSrcField(0x3f) tcpSrcPortFieldWithoutValue := openflow15.NewTcpSrcField(0xffff) nwProtoFieldWithoutValue := openflow15.NewIpProtoField(0xff) @@ -1055,7 +1057,7 @@ func TestNotes(t *testing.T) { } func testNewFlowActionAPIsTest1(t *testing.T) { - brName := ovsDriver.OvsBridgeName + brName := ovsDriver.BridgeName() srcMac1, _ := net.ParseMAC("11:11:11:11:11:11") srcIP1 := net.ParseIP("192.168.2.10") @@ -1080,7 +1082,7 @@ func testNewFlowActionAPIsTest1(t *testing.T) { } func testNewFlowActionAPIsTest2(t *testing.T) { - brName := ovsDriver.OvsBridgeName + brName := ovsDriver.BridgeName() srcMac1, _ := net.ParseMAC("22:22:22:22:22:22") srcIP1 := net.ParseIP("192.168.2.10") @@ -1106,7 +1108,7 @@ func testNewFlowActionAPIsTest2(t *testing.T) { } func testNewFlowActionAPIsTest3(t *testing.T) { - brName := ovsDriver.OvsBridgeName + brName := ovsDriver.BridgeName() // Test action: output in_port inPort1 := uint32(103) @@ -1125,7 +1127,7 @@ func testNewFlowActionAPIsTest3(t *testing.T) { } func testNewFlowActionAPIsTest4(t *testing.T) { - brName := ovsDriver.OvsBridgeName + brName := ovsDriver.BridgeName() //Test action: output to register inPort2 := uint32(104) @@ -1144,7 +1146,7 @@ func testNewFlowActionAPIsTest4(t *testing.T) { } func testNewFlowActionAPIsTest5(t *testing.T) { - brName := ovsDriver.OvsBridgeName + brName := ovsDriver.BridgeName() // Test action: conjunction inPort3 := uint32(105) @@ -1191,7 +1193,7 @@ func testNewFlowActionAPIsTest5(t *testing.T) { } func testNewFlowActionAPIsTest6(t *testing.T) { - brName := ovsDriver.OvsBridgeName + brName := ovsDriver.BridgeName() // Test action: set tun dst addr inPort4 := uint32(106) flow6 := &Flow{ @@ -1211,7 +1213,7 @@ func testNewFlowActionAPIsTest6(t *testing.T) { } func testNewFlowActionAPIsTest7(t *testing.T) { - brName := ovsDriver.OvsBridgeName + brName := ovsDriver.BridgeName() // Test action: move eth_src->dst_dst, move arp_sha->arp_tha, move arp_spa->arp_tpa, // set_field: arp_op=2, eth_src, arp_sha, arp_spa, @@ -1260,7 +1262,7 @@ func testNewFlowActionAPIsTest7(t *testing.T) { } func testNewFlowActionAPIsTest8_1(t *testing.T) { - brName := ovsDriver.OvsBridgeName + brName := ovsDriver.BridgeName() // Test action: ct(commit, table=1, zone=0xff01,exec(load:0xf009->NXM_NX_CT_MARK[])) inPort6 := uint32(108) @@ -1291,7 +1293,7 @@ func testNewFlowActionAPIsTest8_1(t *testing.T) { } func testNewFlowActionAPIsTest8_2(t *testing.T) { - brName := ovsDriver.OvsBridgeName + brName := ovsDriver.BridgeName() // Test action: ct(table=1,zone=NXM_NX_REG1[0..15],nat) inPort6 := uint32(108) @@ -1316,7 +1318,7 @@ func testNewFlowActionAPIsTest8_2(t *testing.T) { } func testNewFlowActionAPIsTest9(t *testing.T) { - brName := ovsDriver.OvsBridgeName + brName := ovsDriver.BridgeName() // Test action: dec_ttl inPort7 := uint32(109) @@ -1335,7 +1337,7 @@ func testNewFlowActionAPIsTest9(t *testing.T) { } func testNewFlowActionAPIsTest10(t *testing.T) { - brName := ovsDriver.OvsBridgeName + brName := ovsDriver.BridgeName() // Test action: ct(commit, exec(move:NXM_OF_ETH_SRC[]->NXM_NX_CT_LABEL, load:0xf009->NXM_NX_CT_MARK[])) // Test match: ct_state=+new-trk @@ -1368,7 +1370,7 @@ func testNewFlowActionAPIsTest10(t *testing.T) { } func testNewFlowActionAPIsTest11(t *testing.T) { - brName := ovsDriver.OvsBridgeName + brName := ovsDriver.BridgeName() //Test match: reg1=0x12/0xffff reg1 := &NXRegister{ @@ -1393,7 +1395,7 @@ func testNewFlowActionAPIsTest11(t *testing.T) { } func testNewFlowActionAPIsTest12(t *testing.T) { - brName := ovsDriver.OvsBridgeName + brName := ovsDriver.BridgeName() // Test group groupId := uint32(11) @@ -1431,7 +1433,7 @@ func testNewFlowActionAPIsTest12(t *testing.T) { } func TestNewFlowActionAPIs(t *testing.T) { - brName := ovsDriver.OvsBridgeName + brName := ovsDriver.BridgeName() log.Infof("Enable monitor flows on table %d in bridge %s", ofActor.inputTable.TableId, brName) ofActor.Switch.EnableMonitor() @@ -1451,7 +1453,7 @@ func TestNewFlowActionAPIs(t *testing.T) { } func TestSetTunnelMetadata(t *testing.T) { - brName := ovsDriver.OvsBridgeName + brName := ovsDriver.BridgeName() log.Infof("Enable monitor flows on table %d in bridge %s", ofActor.inputTable.TableId, brName) ofActor.Switch.EnableMonitor() @@ -1528,7 +1530,7 @@ func TestModPort(t *testing.T) { brName := "br4modPort" ovsBr := prepareControllerAndSwitch(t, app, ctrl, brName) defer func() { - assert.Nilf(t, ovsBr.DeleteBridge(brName), "Failed to delete br %s", brName) + assert.NoError(t, ovsBr.Delete()) ctrl.Delete() }() @@ -1555,7 +1557,7 @@ func TestCtMatch(t *testing.T) { brName := "br4ctMatch" ovsBr := prepareControllerAndSwitch(t, app, ctrl, brName) defer func() { - assert.Nilf(t, ovsBr.DeleteBridge(brName), "Failed to delete br %s", brName) + assert.NoError(t, ovsBr.Delete()) ctrl.Delete() }() @@ -1628,7 +1630,7 @@ func TestIPv6Flows(t *testing.T) { brName := "br4IPv6" ovsBr := prepareControllerAndSwitch(t, app, ctrl, brName) defer func() { - assert.Nilf(t, ovsBr.DeleteBridge(brName), "Failed to delete br %s", brName) + assert.NoError(t, ovsBr.Delete()) ctrl.Delete() }() @@ -1734,8 +1736,8 @@ func TestIPv6Flows(t *testing.T) { "set_field:2001:1:1:1443::ab:1004->nd_target,set_field:136->icmpv6_type,goto_table:1") } -func testNXExtensionNote(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { - brName := ovsBr.OvsBridgeName +func testNXExtensionNote(ofApp *OfActor, ovsBr *internal.OvsDriver, t *testing.T) { + brName := ovsBr.BridgeName() log.Infof("Enable monitor flows on Table %d in bridge %s", ofApp.inputTable.TableId, brName) ofApp.Switch.EnableMonitor() srcMac1, _ := net.ParseMAC("33:33:11:11:11:11") @@ -1754,8 +1756,8 @@ func testNXExtensionNote(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { require.NoError(t, err) } -func testNXExtensionLearn(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { - brName := ovsBr.OvsBridgeName +func testNXExtensionLearn(ofApp *OfActor, ovsBr *internal.OvsDriver, t *testing.T) { + brName := ovsBr.BridgeName() log.Infof("Enable monitor flows on Table %d in bridge %s", ofApp.inputTable.TableId, brName) ofApp.Switch.EnableMonitor() srcMac1, _ := net.ParseMAC("22:22:11:11:11:11") @@ -1811,9 +1813,9 @@ func testNXExtensionLearn(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { } -func testNXExtensionsTest1(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { +func testNXExtensionsTest1(ofApp *OfActor, ovsBr *internal.OvsDriver, t *testing.T) { // Test action: load mac to src mac - brName := ovsBr.OvsBridgeName + brName := ovsBr.BridgeName() srcMac1, _ := net.ParseMAC("11:11:11:11:11:11") srcIP1 := net.ParseIP("192.168.1.10") flow1, err := ofApp.inputTable.NewFlow(FlowMatch{ @@ -1834,9 +1836,9 @@ func testNXExtensionsTest1(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { "set_field:11:11:11:22:22:22->eth_src,goto_table:1") } -func testNXExtensionsTest2_1(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { +func testNXExtensionsTest2_1(ofApp *OfActor, ovsBr *internal.OvsDriver, t *testing.T) { // Test action: move src mac to dst mac - brName := ovsBr.OvsBridgeName + brName := ovsBr.BridgeName() srcIP1 := net.ParseIP("192.168.1.10") srcMac2, _ := net.ParseMAC("11:11:11:11:11:22") flow2, err := ofApp.inputTable.NewFlow(FlowMatch{ @@ -1857,10 +1859,10 @@ func testNXExtensionsTest2_1(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { "move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],goto_table:1") } -func testNXExtensionsTest2_2(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { +func testNXExtensionsTest2_2(ofApp *OfActor, ovsBr *internal.OvsDriver, t *testing.T) { // Test action: move src reg to dst reg, testing NXM match field // support in CopyField action. - brName := ovsBr.OvsBridgeName + brName := ovsBr.BridgeName() srcIP1 := net.ParseIP("192.168.1.10") srcMac2, _ := net.ParseMAC("11:11:11:11:11:22") flow2, err := ofApp.inputTable.NewFlow(FlowMatch{ @@ -1881,9 +1883,9 @@ func testNXExtensionsTest2_2(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { "move:NXM_NX_REG5[]->NXM_NX_REG6[],goto_table:1") } -func testNXExtensionsTest3(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { +func testNXExtensionsTest3(ofApp *OfActor, ovsBr *internal.OvsDriver, t *testing.T) { // Test action: output in_port - brName := ovsBr.OvsBridgeName + brName := ovsBr.BridgeName() inPort1 := uint32(3) flow3, err := ofApp.inputTable.NewFlow(FlowMatch{ Priority: 100, @@ -1895,9 +1897,9 @@ func testNXExtensionsTest3(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { "IN_PORT") } -func testNXExtensionsTest4(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { +func testNXExtensionsTest4(ofApp *OfActor, ovsBr *internal.OvsDriver, t *testing.T) { //Test action: output to register - brName := ovsBr.OvsBridgeName + brName := ovsBr.BridgeName() inPort2 := uint32(4) flow4, err := ofApp.inputTable.NewFlow(FlowMatch{ Priority: 100, @@ -1910,9 +1912,9 @@ func testNXExtensionsTest4(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { "output:NXM_NX_REG1[5..10]") } -func testNXExtensionsTest5(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { +func testNXExtensionsTest5(ofApp *OfActor, ovsBr *internal.OvsDriver, t *testing.T) { // Test action: conjunction - brName := ovsBr.OvsBridgeName + brName := ovsBr.BridgeName() inPort3 := uint32(5) flow5, err := ofApp.inputTable.NewFlow(FlowMatch{ Priority: 100, @@ -1953,9 +1955,9 @@ func testNXExtensionsTest5(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { "br: %s, target flow still found in OVS after deleting it", brName) } -func testNXExtensionsTest6(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { +func testNXExtensionsTest6(ofApp *OfActor, ovsBr *internal.OvsDriver, t *testing.T) { // Test action: set tun dst addr - brName := ovsBr.OvsBridgeName + brName := ovsBr.BridgeName() inPort4 := uint32(6) flow6, err := ofApp.inputTable.NewFlow(FlowMatch{ Priority: 100, @@ -1970,11 +1972,11 @@ func testNXExtensionsTest6(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { "set_field:192.168.1.100->tun_dst,goto_table:1") } -func testNXExtensionsTest7(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { +func testNXExtensionsTest7(ofApp *OfActor, ovsBr *internal.OvsDriver, t *testing.T) { // Test action: move eth_src->dst_dst, move arp_sha->arp_tha, move arp_spa->arp_tpa, // set_field: arp_op=2, eth_src, arp_sha, arp_spa, // output:IN_PORT - brName := ovsBr.OvsBridgeName + brName := ovsBr.BridgeName() inPort5 := uint32(7) flow7, err := ofApp.inputTable.NewFlow(FlowMatch{ Priority: 100, @@ -2016,9 +2018,9 @@ func testNXExtensionsTest7(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { "move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[],set_field:2->arp_op,set_field:11:11:11:11:11:22->eth_src,set_field:11:11:11:11:11:22->arp_sha,set_field:192.168.1.100->arp_spa,IN_PORT") } -func testNXExtensionsTest8(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { +func testNXExtensionsTest8(ofApp *OfActor, ovsBr *internal.OvsDriver, t *testing.T) { // Test action: ct(commit, table=1, zone=0xff01,exec(load:0xf009->NXM_NX_CT_MARK[])) - brName := ovsBr.OvsBridgeName + brName := ovsBr.BridgeName() inPort6 := uint32(8) flow8, err := ofApp.inputTable.NewFlow(FlowMatch{ Priority: 100, @@ -2052,9 +2054,9 @@ func testNXExtensionsTest8(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { "ct(table=1,zone=65281,nat),goto_table:1") } -func testNXExtensionsTest9(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { +func testNXExtensionsTest9(ofApp *OfActor, ovsBr *internal.OvsDriver, t *testing.T) { // Test action: dec_ttl - brName := ovsBr.OvsBridgeName + brName := ovsBr.BridgeName() inPort7 := uint32(9) flow9, err := ofApp.inputTable.NewFlow(FlowMatch{ Priority: 100, @@ -2069,10 +2071,10 @@ func testNXExtensionsTest9(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { "dec_ttl,goto_table:1") } -func testNXExtensionsTest10(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { +func testNXExtensionsTest10(ofApp *OfActor, ovsBr *internal.OvsDriver, t *testing.T) { // Test action: ct(commit, exec(move:NXM_OF_ETH_SRC[]->NXM_NX_CT_LABEL, load:0xf009->NXM_NX_CT_MARK[])) // Test match: ct_state=+new-trk - brName := ovsBr.OvsBridgeName + brName := ovsBr.BridgeName() ctStates := openflow15.NewCTStates() ctStates.SetNew() ctStates.UnsetTrk() @@ -2100,8 +2102,8 @@ func testNXExtensionsTest10(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { "ct(commit,exec(move:NXM_OF_ETH_SRC[]->NXM_NX_CT_LABEL[0..47],set_field:0xf009/0xffff->ct_mark)),goto_table:1") } -func testNXExtensionsTest11(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { - brName := ovsBr.OvsBridgeName +func testNXExtensionsTest11(ofApp *OfActor, ovsBr *internal.OvsDriver, t *testing.T) { + brName := ovsBr.BridgeName() status := ofApp.Switch.CheckStatus(1) assert.True(t, status, "Failed to check Switch status.") //Test match: reg1=0x12/0xffff @@ -2124,8 +2126,8 @@ func testNXExtensionsTest11(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { "ct(commit),goto_table:1") } -func testNXExtensionsTest12(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { - brName := ovsBr.OvsBridgeName +func testNXExtensionsTest12(ofApp *OfActor, ovsBr *internal.OvsDriver, t *testing.T) { + brName := ovsBr.BridgeName() //Test match: ct_mark=0x20/0x20 var mask = uint32(0x20) flow12, err := ofApp.inputTable.NewFlow(FlowMatch{ @@ -2140,9 +2142,9 @@ func testNXExtensionsTest12(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { "goto_table:1") } -func testNXExtensionsTest13(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { +func testNXExtensionsTest13(ofApp *OfActor, ovsBr *internal.OvsDriver, t *testing.T) { // Test group - brName := ovsBr.OvsBridgeName + brName := ovsBr.BridgeName() groupId := uint32(1) group1 := NewGroup(groupId, GroupSelect, ofApp.Switch) @@ -2176,8 +2178,8 @@ func testNXExtensionsTest13(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { verifyGroup(t, brName, group1, "select", "bucket=bucket_id:50,actions=ct(commit,nat(src=10.0.0.240,random))", "", false) } -func testNXExtensionsWithOFApplication(ofApp *OfActor, ovsBr *OvsDriver, t *testing.T) { - brName := ovsBr.OvsBridgeName +func testNXExtensionsWithOFApplication(ofApp *OfActor, ovsBr *internal.OvsDriver, t *testing.T) { + brName := ovsBr.BridgeName() log.Infof("Enable monitor flows on table %d in bridge %s", ofApp.inputTable.TableId, brName) ofApp.Switch.EnableMonitor() @@ -2281,7 +2283,7 @@ func ofctlGroupDump(brName string) ([]string, error) { // Test flows using write_actions func TestWriteactionsFlows(t *testing.T) { - brName := ovsDriver.OvsBridgeName + brName := ovsDriver.BridgeName() log.Infof("Enable monitor flows on table %d in bridge %s", ofActor.inputTable.TableId, brName) ofActor.Switch.EnableMonitor() diff --git a/ofctrl/ofpacket_test.go b/ofctrl/ofpacket_test.go index 7e5832c3..fa1b96a5 100644 --- a/ofctrl/ofpacket_test.go +++ b/ofctrl/ofpacket_test.go @@ -43,7 +43,7 @@ func TestPacketIn_PacketOut(t *testing.T) { brName := "br4pkt" ovsBr := prepareControllerAndSwitch(t, app.OfActor, ctrl, brName) defer func() { - assert.Nilf(t, ovsBr.DeleteBridge(brName), "Failed to delete br %s", brName) + assert.NoError(t, ovsBr.Delete()) ctrl.Delete() }() app.Switch.EnableMonitor() @@ -125,7 +125,7 @@ func TestNxOutputAndSendController(t *testing.T) { brName := "br4sendcontroller" ovsBr := prepareControllerAndSwitch(t, app.OfActor, ctrl, brName) defer func() { - assert.Nilf(t, ovsBr.DeleteBridge(brName), "Failed to delete br %s", brName) + assert.NoError(t, ovsBr.Delete()) ctrl.Delete() }() diff --git a/ofctrl/ovsdbDriver.go b/ofctrl/ovsdbDriver.go deleted file mode 100644 index 2d8bf2dc..00000000 --- a/ofctrl/ovsdbDriver.go +++ /dev/null @@ -1,637 +0,0 @@ -package ofctrl - -import ( - "errors" - "fmt" - "reflect" - "sync" - "time" - - "github.com/contiv/libovsdb" - log "github.com/sirupsen/logrus" -) - -// OVS driver state -type OvsDriver struct { - // OVS client - ovsClient *libovsdb.OvsdbClient - - // Name of the OVS bridge - OvsBridgeName string - - // OVSDB cache - ovsdbCache map[string]map[string]libovsdb.Row - - // read/write lock for accessing the cache - lock sync.RWMutex -} - -// Create a new OVS driver -func NewOvsDriver(bridgeName string) *OvsDriver { - ovsDriver := new(OvsDriver) - - // connect to OVS - ovs, err := libovsdb.Connect("localhost", 6640) - if err != nil { - log.Fatal("Failed to connect to ovsdb") - } - - // Setup state - ovsDriver.ovsClient = ovs - ovsDriver.OvsBridgeName = bridgeName - ovsDriver.ovsdbCache = make(map[string]map[string]libovsdb.Row) - - go func() { - // Register for notifications - ovs.Register(ovsDriver) - - // Populate initial state into cache - initial, _ := ovs.MonitorAll("Open_vSwitch", "") - ovsDriver.populateCache(*initial) - }() - - // HACK: sleep the main thread so that Cache can be populated - time.Sleep(1 * time.Second) - - // Create the default bridge instance - err = ovsDriver.CreateBridge(ovsDriver.OvsBridgeName) - if err != nil { - log.Fatalf("Error creating the default bridge. Err: %v", err) - } - - // Return the new OVS driver - return ovsDriver -} - -// Delete : Cleanup the ovsdb driver. delete the bridge we created. -func (d *OvsDriver) Delete() error { - if d.ovsClient != nil { - d.DeleteBridge(d.OvsBridgeName) - log.Infof("Deleting OVS bridge: %s", d.OvsBridgeName) - (*d.ovsClient).Disconnect() - } - - return nil -} - -// Populate local cache of ovs state -func (self *OvsDriver) populateCache(updates libovsdb.TableUpdates) { - // lock the cache for write - self.lock.Lock() - defer self.lock.Unlock() - - for table, tableUpdate := range updates.Updates { - if _, ok := self.ovsdbCache[table]; !ok { - self.ovsdbCache[table] = make(map[string]libovsdb.Row) - - } - for uuid, row := range tableUpdate.Rows { - empty := libovsdb.Row{} - if !reflect.DeepEqual(row.New, empty) { - self.ovsdbCache[table][uuid] = row.New - } else { - delete(self.ovsdbCache[table], uuid) - } - } - } -} - -// Dump the contents of the cache into stdout -func (self *OvsDriver) PrintCache() { - // lock the cache for read - self.lock.RLock() - defer self.lock.RUnlock() - - fmt.Printf("OvsDB Cache: \n") - - // walk the local cache - for tName, table := range self.ovsdbCache { - fmt.Printf("Table: %s\n", tName) - for uuid, row := range table { - fmt.Printf(" Row: UUID: %s\n", uuid) - for fieldName, value := range row.Fields { - fmt.Printf(" Field: %s, Value: %+v\n", fieldName, value) - } - } - } -} - -// Get the UUID for root -func (self *OvsDriver) getRootUuid() libovsdb.UUID { - // lock the cache for read - self.lock.RLock() - defer self.lock.RUnlock() - - // find the matching uuid - for uuid := range self.ovsdbCache["Open_vSwitch"] { - return libovsdb.UUID{GoUuid: uuid} - } - return libovsdb.UUID{} -} - -// Wrapper for ovsDB transaction -func (self *OvsDriver) ovsdbTransact(ops []libovsdb.Operation) error { - // Print out what we are sending - log.Debugf("Transaction: %+v\n", ops) - - // Perform OVSDB transaction - reply, _ := self.ovsClient.Transact("Open_vSwitch", ops...) - - if len(reply) < len(ops) { - log.Errorf("Unexpected number of replies. Expected: %d, Recvd: %d", len(ops), len(reply)) - return errors.New("OVS transaction failed. Unexpected number of replies") - } - - // Parse reply and look for errors - for i, o := range reply { - if o.Error != "" && i < len(ops) { - return errors.New("OVS Transaction failed err " + o.Error + "Details: " + o.Details) - } else if o.Error != "" { - return errors.New("OVS Transaction failed err " + o.Error + "Details: " + o.Details) - } - } - - // Return success - return nil -} - -// **************** OVS driver API ******************** -func (self *OvsDriver) CreateBridge(bridgeName string) error { - namedUuidStr := "dummy" - protocols := []string{"OpenFlow10", "OpenFlow11", "OpenFlow12", "OpenFlow13", "OpenFlow14", "OpenFlow15"} - - // If the bridge already exists, just return - // FIXME: should we delete the old bridge and create new one? - if self.IsBridgePresent(bridgeName) { - return nil - } - - // simple insert/delete operation - bridge := make(map[string]interface{}) - bridge["name"] = bridgeName - bridge["protocols"], _ = libovsdb.NewOvsSet(protocols) - bridge["fail_mode"] = "secure" - brOp := libovsdb.Operation{ - Op: "insert", - Table: "Bridge", - Row: bridge, - UUIDName: namedUuidStr, - } - - // Inserting/Deleting a Bridge row in Bridge table requires mutating - // the open_vswitch table. - brUuid := []libovsdb.UUID{{GoUuid: namedUuidStr}} - mutateUuid := brUuid - mutateSet, _ := libovsdb.NewOvsSet(mutateUuid) - mutation := libovsdb.NewMutation("bridges", "insert", mutateSet) - condition := libovsdb.NewCondition("_uuid", "==", self.getRootUuid()) - - // simple mutate operation - mutateOp := libovsdb.Operation{ - Op: "mutate", - Table: "Open_vSwitch", - Mutations: []interface{}{mutation}, - Where: []interface{}{condition}, - } - - operations := []libovsdb.Operation{brOp, mutateOp} - - // operations := []libovsdb.Operation{brOp} - return self.ovsdbTransact(operations) -} - -// Delete a bridge from ovs -func (self *OvsDriver) DeleteBridge(bridgeName string) error { - // lock the cache for read - self.lock.RLock() - defer self.lock.RUnlock() - - namedUuidStr := "dummy" - brUuid := []libovsdb.UUID{{GoUuid: namedUuidStr}} - - // simple insert/delete operation - condition := libovsdb.NewCondition("name", "==", bridgeName) - brOp := libovsdb.Operation{ - Op: "delete", - Table: "Bridge", - Where: []interface{}{condition}, - } - - // also fetch the br-uuid from cache - for uuid, row := range self.ovsdbCache["Bridge"] { - name := row.Fields["name"].(string) - if name == bridgeName { - brUuid = []libovsdb.UUID{{GoUuid: uuid}} - break - } - } - - // Inserting/Deleting a Bridge row in Bridge table requires mutating - // the open_vswitch table. - mutateUuid := brUuid - mutateSet, _ := libovsdb.NewOvsSet(mutateUuid) - mutation := libovsdb.NewMutation("bridges", "delete", mutateSet) - condition = libovsdb.NewCondition("_uuid", "==", self.getRootUuid()) - - // simple mutate operation - mutateOp := libovsdb.Operation{ - Op: "mutate", - Table: "Open_vSwitch", - Mutations: []interface{}{mutation}, - Where: []interface{}{condition}, - } - - operations := []libovsdb.Operation{brOp, mutateOp} - return self.ovsdbTransact(operations) -} - -// Create an internal port in OVS -func (self *OvsDriver) CreatePort(intfName, intfType string, vlanTag uint) error { - portUuidStr := intfName - intfUuidStr := fmt.Sprintf("Intf%s", intfName) - portUuid := []libovsdb.UUID{{GoUuid: portUuidStr}} - intfUuid := []libovsdb.UUID{{GoUuid: intfUuidStr}} - opStr := "insert" - var err error = nil - - // insert/delete a row in Interface table - intf := make(map[string]interface{}) - intf["name"] = intfName - intf["type"] = intfType - - // Add an entry in Interface table - intfOp := libovsdb.Operation{ - Op: opStr, - Table: "Interface", - Row: intf, - UUIDName: intfUuidStr, - } - - // insert/delete a row in Port table - port := make(map[string]interface{}) - port["name"] = intfName - if vlanTag != 0 { - port["vlan_mode"] = "access" - port["tag"] = vlanTag - } else { - port["vlan_mode"] = "trunk" - } - - port["interfaces"], err = libovsdb.NewOvsSet(intfUuid) - if err != nil { - return err - } - - // Add an entry in Port table - portOp := libovsdb.Operation{ - Op: opStr, - Table: "Port", - Row: port, - UUIDName: portUuidStr, - } - - // mutate the Ports column of the row in the Bridge table - mutateSet, _ := libovsdb.NewOvsSet(portUuid) - mutation := libovsdb.NewMutation("ports", opStr, mutateSet) - condition := libovsdb.NewCondition("name", "==", self.OvsBridgeName) - mutateOp := libovsdb.Operation{ - Op: "mutate", - Table: "Bridge", - Mutations: []interface{}{mutation}, - Where: []interface{}{condition}, - } - - // Perform OVS transaction - operations := []libovsdb.Operation{intfOp, portOp, mutateOp} - return self.ovsdbTransact(operations) -} - -// Delete a port from OVS -func (self *OvsDriver) DeletePort(intfName string) error { - // lock the cache for read - self.lock.RLock() - defer self.lock.RUnlock() - - portUuidStr := intfName - portUuid := []libovsdb.UUID{{GoUuid: portUuidStr}} - opStr := "delete" - - // insert/delete a row in Interface table - condition := libovsdb.NewCondition("name", "==", intfName) - intfOp := libovsdb.Operation{ - Op: opStr, - Table: "Interface", - Where: []interface{}{condition}, - } - - // insert/delete a row in Port table - condition = libovsdb.NewCondition("name", "==", intfName) - portOp := libovsdb.Operation{ - Op: opStr, - Table: "Port", - Where: []interface{}{condition}, - } - - // also fetch the port-uuid from cache - for uuid, row := range self.ovsdbCache["Port"] { - name := row.Fields["name"].(string) - if name == intfName { - portUuid = []libovsdb.UUID{{GoUuid: uuid}} - break - } - } - - // mutate the Ports column of the row in the Bridge table - mutateSet, _ := libovsdb.NewOvsSet(portUuid) - mutation := libovsdb.NewMutation("ports", opStr, mutateSet) - condition = libovsdb.NewCondition("name", "==", self.OvsBridgeName) - mutateOp := libovsdb.Operation{ - Op: "mutate", - Table: "Bridge", - Mutations: []interface{}{mutation}, - Where: []interface{}{condition}, - } - - // Perform OVS transaction - operations := []libovsdb.Operation{intfOp, portOp, mutateOp} - return self.ovsdbTransact(operations) -} - -// Create a VTEP port on the OVS -func (self *OvsDriver) CreateVtep(intfName string, vtepRemoteIP string) error { - portUuidStr := intfName - intfUuidStr := fmt.Sprintf("Intf%s", intfName) - portUuid := []libovsdb.UUID{{GoUuid: portUuidStr}} - intfUuid := []libovsdb.UUID{{GoUuid: intfUuidStr}} - opStr := "insert" - intfType := "vxlan" - var err error = nil - - // insert/delete a row in Interface table - intf := make(map[string]interface{}) - intf["name"] = intfName - intf["type"] = intfType - - // Special handling for VTEP ports - intfOptions := make(map[string]interface{}) - intfOptions["remote_ip"] = vtepRemoteIP - intfOptions["key"] = "flow" // Insert VNI per flow - - intf["options"], err = libovsdb.NewOvsMap(intfOptions) - if err != nil { - log.Errorf("error '%s' creating options from %v \n", err, intfOptions) - return err - } - - // Add an entry in Interface table - intfOp := libovsdb.Operation{ - Op: opStr, - Table: "Interface", - Row: intf, - UUIDName: intfUuidStr, - } - - // insert/delete a row in Port table - port := make(map[string]interface{}) - port["name"] = intfName - port["vlan_mode"] = "trunk" - - port["interfaces"], err = libovsdb.NewOvsSet(intfUuid) - if err != nil { - return err - } - - // Add an entry in Port table - portOp := libovsdb.Operation{ - Op: opStr, - Table: "Port", - Row: port, - UUIDName: portUuidStr, - } - - // mutate the Ports column of the row in the Bridge table - mutateSet, _ := libovsdb.NewOvsSet(portUuid) - mutation := libovsdb.NewMutation("ports", opStr, mutateSet) - condition := libovsdb.NewCondition("name", "==", self.OvsBridgeName) - mutateOp := libovsdb.Operation{ - Op: "mutate", - Table: "Bridge", - Mutations: []interface{}{mutation}, - Where: []interface{}{condition}, - } - - // Perform OVS transaction - operations := []libovsdb.Operation{intfOp, portOp, mutateOp} - return self.ovsdbTransact(operations) -} - -// Delete a VTEP port -func (self *OvsDriver) DeleteVtep(intfName string) error { - return self.DeletePort(intfName) -} - -// Add controller configuration to OVS -func (self *OvsDriver) AddController(ipAddr string, portNo uint16) error { - // Format target string - target := fmt.Sprintf("tcp:%s:%d", ipAddr, portNo) - ctrlerUuidStr := fmt.Sprintf("local") - ctrlerUuid := []libovsdb.UUID{{GoUuid: ctrlerUuidStr}} - - // If controller already exists, nothing to do - if self.IsControllerPresent(ipAddr, portNo) { - return nil - } - - // insert a row in Controller table - controller := make(map[string]interface{}) - controller["target"] = target - - // Add an entry in Controller table - ctrlerOp := libovsdb.Operation{ - Op: "insert", - Table: "Controller", - Row: controller, - UUIDName: ctrlerUuidStr, - } - - // mutate the Controller column of the row in the Bridge table - mutateSet, _ := libovsdb.NewOvsSet(ctrlerUuid) - mutation := libovsdb.NewMutation("controller", "insert", mutateSet) - condition := libovsdb.NewCondition("name", "==", self.OvsBridgeName) - mutateOp := libovsdb.Operation{ - Op: "mutate", - Table: "Bridge", - Mutations: []interface{}{mutation}, - Where: []interface{}{condition}, - } - - // Perform OVS transaction - operations := []libovsdb.Operation{ctrlerOp, mutateOp} - return self.ovsdbTransact(operations) -} - -func (self *OvsDriver) RemoveController(target string) error { - // FIXME: - return nil -} - -// Check the local cache and see if the portname is taken already -// HACK alert: This is used to pick next port number instead of managing -// port number space actively across agent restarts -func (self *OvsDriver) IsPortNamePresent(intfName string) bool { - // lock the cache for read - self.lock.RLock() - defer self.lock.RUnlock() - - // walk the local cache - for tName, table := range self.ovsdbCache { - if tName == "Port" { - for _, row := range table { - for fieldName, value := range row.Fields { - if fieldName == "name" { - if value == intfName { - // Interface name exists. - return true - } - } - } - } - } - } - - // We could not find the interface name - return false -} - -// Check if the bridge entry already exists -func (self *OvsDriver) IsBridgePresent(bridgeName string) bool { - // lock the cache for read - self.lock.RLock() - defer self.lock.RUnlock() - - // walk the bridge table in cache - for tName, table := range self.ovsdbCache { - if tName == "Bridge" { - for _, row := range table { - for fieldName, value := range row.Fields { - if fieldName == "name" { - if value == bridgeName { - // Interface name exists. - return true - } - } - } - } - } - } - - // We could not find the interface name - return false -} - -// Check if Controller already exists -func (self *OvsDriver) IsControllerPresent(ipAddr string, portNo uint16) bool { - // lock the cache for read - self.lock.RLock() - defer self.lock.RUnlock() - - // walk the locak cache - target := fmt.Sprintf("tcp:%s:%d", ipAddr, portNo) - for tName, table := range self.ovsdbCache { - if tName == "Controller" { - for _, row := range table { - for fieldName, value := range row.Fields { - if fieldName == "target" { - if value == target { - // Controller exists. - return true - } - } - } - } - } - } - - // We could not find the interface name - return false -} - -// Check if VTEP already exists -func (self *OvsDriver) IsVtepPresent(remoteIP string) (bool, string) { - // lock the cache for read - self.lock.RLock() - defer self.lock.RUnlock() - - // walk the local cache - for tName, table := range self.ovsdbCache { - if tName == "Interface" { - for _, row := range table { - options := row.Fields["options"] - switch optMap := options.(type) { - case libovsdb.OvsMap: - if optMap.GoMap["remote_ip"] == remoteIP { - value := row.Fields["name"] - switch t := value.(type) { - case string: - return true, t - default: - // return false, "" - } - } - default: - // return false, "" - } - } - } - } - - // We could not find the interface name - return false, "" -} - -// Return OFP port number for an interface -func (self *OvsDriver) GetOfpPortNo(intfName string) (uint32, error) { - retryNo := 0 - condition := libovsdb.NewCondition("name", "==", intfName) - selectOp := libovsdb.Operation{ - Op: "select", - Table: "Interface", - Where: []interface{}{condition}, - } - - for { - row, err := self.ovsClient.Transact("Open_vSwitch", selectOp) - - if err == nil && len(row) > 0 && len(row[0].Rows) > 0 { - value := row[0].Rows[0]["ofport"] - if reflect.TypeOf(value).Kind() == reflect.Float64 { - //retry few more time. Due to asynchronous call between - //port creation and populating ovsdb entry for the interface - //may not be populated instantly. - var ofpPort uint32 = uint32(reflect.ValueOf(value).Float()) - return ofpPort, nil - } - } - time.Sleep(200 * time.Millisecond) - - if retryNo == 5 { - return 0, errors.New("ofPort not found") - } - retryNo++ - } -} - -// ************************ Notification handler for OVS DB changes **************** -func (self *OvsDriver) Update(context interface{}, tableUpdates libovsdb.TableUpdates) { - // fmt.Printf("Received OVS update: %+v\n\n", tableUpdates) - self.populateCache(tableUpdates) -} -func (self *OvsDriver) Disconnected(ovsClient *libovsdb.OvsdbClient) { - log.Errorf("OVS BD client disconnected") -} -func (self *OvsDriver) Locked([]interface{}) { -} -func (self *OvsDriver) Stolen([]interface{}) { -} -func (self *OvsDriver) Echo([]interface{}) { -}