From 94d4d2687722ecb6602874ac761f3de892b9965a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Thu, 14 Dec 2023 18:10:07 -0500 Subject: [PATCH 01/38] Makefile: Add update-ovsdb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- Makefile | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Makefile b/Makefile index b667aeb35e1..709f9c25c6c 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,8 @@ GOPATH ?= $(shell $(GO) env GOPATH) CGO_LDFLAGS_ALLOW ?= (-Wl,-wrap,pthread_create)|(-Wl,-z,now) SPHINXENV=doc/.sphinx/venv/bin/activate SPHINXPIPPATH=doc/.sphinx/venv/bin/pip +OVN_MINVER=23.03.0 +OVS_MINVER=2.15.0 ifneq "$(wildcard vendor)" "" RAFT_PATH=$(CURDIR)/vendor/raft @@ -106,6 +108,19 @@ endif cd test/mini-oidc && $(GO) mod tidy --go=1.20 @echo "Dependencies updated" +.PHONY: update-ovsdb +update-ovsdb: + go install github.com/ovn-org/libovsdb/cmd/modelgen@main + rm -Rf internal/server/network/openvswitch/schema + mkdir internal/server/network/openvswitch/schema + curl -s https://raw.githubusercontent.com/ovn-org/ovn/v$(OVN_MINVER)/ovn-nb.ovsschema -o internal/server/network/openvswitch/schema/ovn-nb.json + curl -s https://raw.githubusercontent.com/ovn-org/ovn/v$(OVN_MINVER)/ovn-sb.ovsschema -o internal/server/network/openvswitch/schema/ovn-sb.json + curl -s https://raw.githubusercontent.com/openvswitch/ovs/v$(OVS_MINVER)/vswitchd/vswitch.ovsschema -o internal/server/network/openvswitch/schema/ovs.json + modelgen -o internal/server/network/openvswitch/schema/ovn-nb internal/server/network/openvswitch/schema/ovn-nb.json + modelgen -o internal/server/network/openvswitch/schema/ovn-sb internal/server/network/openvswitch/schema/ovn-sb.json + modelgen -o internal/server/network/openvswitch/schema/ovs internal/server/network/openvswitch/schema/ovs.json + rm internal/server/network/openvswitch/schema/*.json + .PHONY: update-protobuf update-protobuf: protoc --go_out=. ./internal/migration/migrate.proto From cdef3c32765c677866c404da057c836a7445266b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Mon, 18 Dec 2023 13:24:24 -0500 Subject: [PATCH 02/38] gomod: Add libovsdb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- go.mod | 11 ++++++++++- go.sum | 21 ++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index bbd19771b36..f90f43e412b 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/flosch/pongo2 v0.0.0-20200913210552-0d938eb266f3 github.com/fvbommel/sortorder v1.1.0 github.com/go-acme/lego/v4 v4.14.2 + github.com/go-logr/logr v1.3.0 github.com/google/gopacket v1.1.19 github.com/google/uuid v1.5.0 github.com/gorilla/mux v1.8.1 @@ -36,6 +37,7 @@ require ( github.com/olekukonko/tablewriter v0.0.5 github.com/openfga/go-sdk v0.3.1-go1.20 github.com/osrg/gobgp/v3 v3.21.0 + github.com/ovn-org/libovsdb v0.6.1-0.20230912124059-239822fe891a github.com/pkg/sftp v1.13.6 github.com/pkg/xattr v0.4.9 github.com/robfig/cron/v3 v3.0.1 @@ -59,7 +61,11 @@ require ( ) require ( + github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // 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.2.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect @@ -69,7 +75,6 @@ require ( github.com/eapache/queue v1.1.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-jose/go-jose/v3 v3.0.1 // indirect - github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/golang/protobuf v1.5.3 // indirect @@ -88,6 +93,7 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mdlayher/socket v0.4.1 // indirect github.com/minio/md5-simd v1.1.2 // indirect github.com/minio/sha256-simd v1.0.1 // indirect @@ -101,6 +107,9 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect + github.com/prometheus/client_golang v1.16.0 // indirect + github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/rs/cors v1.10.1 // indirect diff --git a/go.sum b/go.sum index 3ea5d09f1ed..d41ba97ec39 100644 --- a/go.sum +++ b/go.sum @@ -48,11 +48,20 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV github.com/armon/go-proxyproto v0.1.0 h1:TWWcSsjco7o2itn6r25/5AqKBiWmsiuzsUDLT/MTl7k= github.com/armon/go-proxyproto v0.1.0/go.mod h1:Xj90dce2VKbHzRAeiVQAMBtj4M5oidoXJ8lmgyW21mw= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +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/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= +github.com/cenk/hub v1.0.1 h1:RBwXNOF4a8KjD8BJ08XqN8KbrqaGiQLDrgvUGJSHuPA= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +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.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/checkpoint-restore/go-criu/v6 v6.3.0 h1:mIdrSO2cPNWQY1truPg6uHLXyKHk3Z5Odx4wjKOASzA= github.com/checkpoint-restore/go-criu/v6 v6.3.0/go.mod h1:rrRTN/uSwY2X+BPRl/gkulo9gsKOSAeVp9/K2tv7xZI= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -297,6 +306,8 @@ github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.19 h1:fhGleo2h1p8tVChob4I9HpmVFIAkKGpiukdrgQbWfGI= github.com/mattn/go-sqlite3 v1.14.19/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mdlayher/ndp v1.0.1 h1:+yAD79/BWyFlvAoeG5ncPS0ItlHP/eVbH7bQ6/+LVA4= github.com/mdlayher/ndp v1.0.1/go.mod h1:rf3wKaWhAYJEXFKpgF8kQ2AxypxVbfNcZbqoAo6fVzk= github.com/mdlayher/netx v0.0.0-20230430222610-7e21880baee8 h1:HMgSn3c16SXca3M+n6fLK2hXJLd4mhKAsZZh7lQfYmQ= @@ -346,6 +357,8 @@ github.com/openfga/go-sdk v0.3.1-go1.20 h1:mH0nczUUEl4dTMTC5WY09o+1sgPcwyL7m4jVu github.com/openfga/go-sdk v0.3.1-go1.20/go.mod h1:W4SNYMSxptGOtA9aGYxsYUmSC7LaZYP7y9qbT36ouCc= github.com/osrg/gobgp/v3 v3.21.0 h1:OCjDIz2duA36tLoQElm8S2ZfxClPqcM9B4SfIlfYQTI= github.com/osrg/gobgp/v3 v3.21.0/go.mod h1:4fbscYpsCk14EO16nTWAdJyErO4MbAZ2zLJmsmeXu/k= +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/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= @@ -369,7 +382,13 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig= github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= +github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -379,7 +398,7 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= From c951403519b49dd1f61e32d312080bf2b27b1993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Thu, 14 Dec 2023 18:14:24 -0500 Subject: [PATCH 03/38] incusd/network/openvswitch: Add OVS and OVN schemas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- .../network/openvswitch/schema/ovn-nb/acl.go | 43 + .../openvswitch/schema/ovn-nb/address_set.go | 14 + .../network/openvswitch/schema/ovn-nb/bfd.go | 30 + .../schema/ovn-nb/chassis_template_var.go | 14 + .../openvswitch/schema/ovn-nb/connection.go | 18 + .../network/openvswitch/schema/ovn-nb/copp.go | 14 + .../openvswitch/schema/ovn-nb/dhcp_options.go | 14 + .../network/openvswitch/schema/ovn-nb/dns.go | 13 + .../schema/ovn-nb/forwarding_group.go | 17 + .../schema/ovn-nb/gateway_chassis.go | 16 + .../openvswitch/schema/ovn-nb/ha_chassis.go | 14 + .../schema/ovn-nb/ha_chassis_group.go | 14 + .../schema/ovn-nb/load_balancer.go | 36 + .../schema/ovn-nb/load_balancer_group.go | 13 + .../ovn-nb/load_balancer_health_check.go | 14 + .../schema/ovn-nb/logical_router.go | 22 + .../schema/ovn-nb/logical_router_policy.go | 28 + .../schema/ovn-nb/logical_router_port.go | 22 + .../ovn-nb/logical_router_static_route.go | 28 + .../schema/ovn-nb/logical_switch.go | 22 + .../schema/ovn-nb/logical_switch_port.go | 27 + .../openvswitch/schema/ovn-nb/meter.go | 25 + .../openvswitch/schema/ovn-nb/meter_band.go | 23 + .../openvswitch/schema/ovn-nb/mirror.go | 29 + .../openvswitch/schema/ovn-nb/model.go | 1974 ++++++++++++++++ .../network/openvswitch/schema/ovn-nb/nat.go | 32 + .../openvswitch/schema/ovn-nb/nb_global.go | 23 + .../openvswitch/schema/ovn-nb/port_group.go | 15 + .../network/openvswitch/schema/ovn-nb/qos.go | 31 + .../network/openvswitch/schema/ovn-nb/ssl.go | 18 + .../schema/ovn-nb/static_mac_binding.go | 15 + .../openvswitch/schema/ovn-sb/address_set.go | 13 + .../network/openvswitch/schema/ovn-sb/bfd.go | 32 + .../openvswitch/schema/ovn-sb/chassis.go | 19 + .../schema/ovn-sb/chassis_private.go | 16 + .../schema/ovn-sb/chassis_template_var.go | 13 + .../openvswitch/schema/ovn-sb/connection.go | 20 + .../schema/ovn-sb/controller_event.go | 23 + .../schema/ovn-sb/datapath_binding.go | 14 + .../openvswitch/schema/ovn-sb/dhcp_options.go | 30 + .../schema/ovn-sb/dhcpv6_options.go | 24 + .../network/openvswitch/schema/ovn-sb/dns.go | 14 + .../openvswitch/schema/ovn-sb/encap.go | 25 + .../network/openvswitch/schema/ovn-sb/fdb.go | 14 + .../schema/ovn-sb/gateway_chassis.go | 16 + .../openvswitch/schema/ovn-sb/ha_chassis.go | 14 + .../schema/ovn-sb/ha_chassis_group.go | 15 + .../openvswitch/schema/ovn-sb/igmp_group.go | 15 + .../openvswitch/schema/ovn-sb/ip_multicast.go | 22 + .../schema/ovn-sb/load_balancer.go | 28 + .../schema/ovn-sb/logical_dp_group.go | 12 + .../openvswitch/schema/ovn-sb/logical_flow.go | 30 + .../openvswitch/schema/ovn-sb/mac_binding.go | 16 + .../openvswitch/schema/ovn-sb/meter.go | 23 + .../openvswitch/schema/ovn-sb/meter_band.go | 22 + .../openvswitch/schema/ovn-sb/mirror.go | 29 + .../openvswitch/schema/ovn-sb/model.go | 1798 +++++++++++++++ .../schema/ovn-sb/multicast_group.go | 15 + .../openvswitch/schema/ovn-sb/port_binding.go | 33 + .../openvswitch/schema/ovn-sb/port_group.go | 13 + .../schema/ovn-sb/rbac_permission.go | 15 + .../openvswitch/schema/ovn-sb/rbac_role.go | 13 + .../openvswitch/schema/ovn-sb/sb_global.go | 17 + .../schema/ovn-sb/service_monitor.go | 33 + .../network/openvswitch/schema/ovn-sb/ssl.go | 18 + .../schema/ovn-sb/static_mac_binding.go | 16 + .../openvswitch/schema/ovs/autoattach.go | 14 + .../network/openvswitch/schema/ovs/bridge.go | 49 + .../openvswitch/schema/ovs/controller.go | 44 + .../schema/ovs/ct_timeout_policy.go | 36 + .../network/openvswitch/schema/ovs/ct_zone.go | 13 + .../openvswitch/schema/ovs/datapath.go | 15 + .../schema/ovs/flow_sample_collector_set.go | 15 + .../openvswitch/schema/ovs/flow_table.go | 26 + .../openvswitch/schema/ovs/interface.go | 62 + .../network/openvswitch/schema/ovs/ipfix.go | 19 + .../network/openvswitch/schema/ovs/manager.go | 28 + .../network/openvswitch/schema/ovs/mirror.go | 21 + .../network/openvswitch/schema/ovs/model.go | 1992 +++++++++++++++++ .../network/openvswitch/schema/ovs/netflow.go | 17 + .../openvswitch/schema/ovs/open_vswitch.go | 28 + .../network/openvswitch/schema/ovs/port.go | 53 + .../network/openvswitch/schema/ovs/qos.go | 15 + .../network/openvswitch/schema/ovs/queue.go | 14 + .../network/openvswitch/schema/ovs/sflow.go | 17 + .../network/openvswitch/schema/ovs/ssl.go | 16 + 86 files changed, 7582 insertions(+) create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/acl.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/address_set.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/bfd.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/chassis_template_var.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/connection.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/copp.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/dhcp_options.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/dns.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/forwarding_group.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/gateway_chassis.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/ha_chassis.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/ha_chassis_group.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/load_balancer.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/load_balancer_group.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/load_balancer_health_check.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/logical_router.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/logical_router_policy.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/logical_router_port.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/logical_router_static_route.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/logical_switch.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/logical_switch_port.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/meter.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/meter_band.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/mirror.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/model.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/nat.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/nb_global.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/port_group.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/qos.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/ssl.go create mode 100644 internal/server/network/openvswitch/schema/ovn-nb/static_mac_binding.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/address_set.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/bfd.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/chassis.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/chassis_private.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/chassis_template_var.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/connection.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/controller_event.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/datapath_binding.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/dhcp_options.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/dhcpv6_options.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/dns.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/encap.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/fdb.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/gateway_chassis.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/ha_chassis.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/ha_chassis_group.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/igmp_group.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/ip_multicast.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/load_balancer.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/logical_dp_group.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/logical_flow.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/mac_binding.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/meter.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/meter_band.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/mirror.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/model.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/multicast_group.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/port_binding.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/port_group.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/rbac_permission.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/rbac_role.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/sb_global.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/service_monitor.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/ssl.go create mode 100644 internal/server/network/openvswitch/schema/ovn-sb/static_mac_binding.go create mode 100644 internal/server/network/openvswitch/schema/ovs/autoattach.go create mode 100644 internal/server/network/openvswitch/schema/ovs/bridge.go create mode 100644 internal/server/network/openvswitch/schema/ovs/controller.go create mode 100644 internal/server/network/openvswitch/schema/ovs/ct_timeout_policy.go create mode 100644 internal/server/network/openvswitch/schema/ovs/ct_zone.go create mode 100644 internal/server/network/openvswitch/schema/ovs/datapath.go create mode 100644 internal/server/network/openvswitch/schema/ovs/flow_sample_collector_set.go create mode 100644 internal/server/network/openvswitch/schema/ovs/flow_table.go create mode 100644 internal/server/network/openvswitch/schema/ovs/interface.go create mode 100644 internal/server/network/openvswitch/schema/ovs/ipfix.go create mode 100644 internal/server/network/openvswitch/schema/ovs/manager.go create mode 100644 internal/server/network/openvswitch/schema/ovs/mirror.go create mode 100644 internal/server/network/openvswitch/schema/ovs/model.go create mode 100644 internal/server/network/openvswitch/schema/ovs/netflow.go create mode 100644 internal/server/network/openvswitch/schema/ovs/open_vswitch.go create mode 100644 internal/server/network/openvswitch/schema/ovs/port.go create mode 100644 internal/server/network/openvswitch/schema/ovs/qos.go create mode 100644 internal/server/network/openvswitch/schema/ovs/queue.go create mode 100644 internal/server/network/openvswitch/schema/ovs/sflow.go create mode 100644 internal/server/network/openvswitch/schema/ovs/ssl.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/acl.go b/internal/server/network/openvswitch/schema/ovn-nb/acl.go new file mode 100644 index 00000000000..85274f394db --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/acl.go @@ -0,0 +1,43 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const ACLTable = "ACL" + +type ( + ACLAction = string + ACLDirection = string + ACLSeverity = string +) + +var ( + ACLActionAllow ACLAction = "allow" + ACLActionAllowRelated ACLAction = "allow-related" + ACLActionAllowStateless ACLAction = "allow-stateless" + ACLActionDrop ACLAction = "drop" + ACLActionReject ACLAction = "reject" + ACLDirectionFromLport ACLDirection = "from-lport" + ACLDirectionToLport ACLDirection = "to-lport" + ACLSeverityAlert ACLSeverity = "alert" + ACLSeverityWarning ACLSeverity = "warning" + ACLSeverityNotice ACLSeverity = "notice" + ACLSeverityInfo ACLSeverity = "info" + ACLSeverityDebug ACLSeverity = "debug" +) + +// ACL defines an object in ACL table +type ACL struct { + UUID string `ovsdb:"_uuid"` + Action ACLAction `ovsdb:"action"` + Direction ACLDirection `ovsdb:"direction"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Label int `ovsdb:"label"` + Log bool `ovsdb:"log"` + Match string `ovsdb:"match"` + Meter *string `ovsdb:"meter"` + Name *string `ovsdb:"name"` + Options map[string]string `ovsdb:"options"` + Priority int `ovsdb:"priority"` + Severity *ACLSeverity `ovsdb:"severity"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/address_set.go b/internal/server/network/openvswitch/schema/ovn-nb/address_set.go new file mode 100644 index 00000000000..3d7eb44de53 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/address_set.go @@ -0,0 +1,14 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const AddressSetTable = "Address_Set" + +// AddressSet defines an object in Address_Set table +type AddressSet struct { + UUID string `ovsdb:"_uuid"` + Addresses []string `ovsdb:"addresses"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Name string `ovsdb:"name"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/bfd.go b/internal/server/network/openvswitch/schema/ovn-nb/bfd.go new file mode 100644 index 00000000000..0a7183d7444 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/bfd.go @@ -0,0 +1,30 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const BFDTable = "BFD" + +type ( + BFDStatus = string +) + +var ( + BFDStatusDown BFDStatus = "down" + BFDStatusInit BFDStatus = "init" + BFDStatusUp BFDStatus = "up" + BFDStatusAdminDown BFDStatus = "admin_down" +) + +// BFD defines an object in BFD table +type BFD struct { + UUID string `ovsdb:"_uuid"` + DetectMult *int `ovsdb:"detect_mult"` + DstIP string `ovsdb:"dst_ip"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + LogicalPort string `ovsdb:"logical_port"` + MinRx *int `ovsdb:"min_rx"` + MinTx *int `ovsdb:"min_tx"` + Options map[string]string `ovsdb:"options"` + Status *BFDStatus `ovsdb:"status"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/chassis_template_var.go b/internal/server/network/openvswitch/schema/ovn-nb/chassis_template_var.go new file mode 100644 index 00000000000..e33f68f7388 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/chassis_template_var.go @@ -0,0 +1,14 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const ChassisTemplateVarTable = "Chassis_Template_Var" + +// ChassisTemplateVar defines an object in Chassis_Template_Var table +type ChassisTemplateVar struct { + UUID string `ovsdb:"_uuid"` + Chassis string `ovsdb:"chassis"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Variables map[string]string `ovsdb:"variables"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/connection.go b/internal/server/network/openvswitch/schema/ovn-nb/connection.go new file mode 100644 index 00000000000..e0fff1b5d04 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/connection.go @@ -0,0 +1,18 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const ConnectionTable = "Connection" + +// Connection defines an object in Connection table +type Connection struct { + UUID string `ovsdb:"_uuid"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + InactivityProbe *int `ovsdb:"inactivity_probe"` + IsConnected bool `ovsdb:"is_connected"` + MaxBackoff *int `ovsdb:"max_backoff"` + OtherConfig map[string]string `ovsdb:"other_config"` + Status map[string]string `ovsdb:"status"` + Target string `ovsdb:"target"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/copp.go b/internal/server/network/openvswitch/schema/ovn-nb/copp.go new file mode 100644 index 00000000000..5de9eca8b2a --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/copp.go @@ -0,0 +1,14 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const CoppTable = "Copp" + +// Copp defines an object in Copp table +type Copp struct { + UUID string `ovsdb:"_uuid"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Meters map[string]string `ovsdb:"meters"` + Name string `ovsdb:"name"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/dhcp_options.go b/internal/server/network/openvswitch/schema/ovn-nb/dhcp_options.go new file mode 100644 index 00000000000..2c848323b1e --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/dhcp_options.go @@ -0,0 +1,14 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const DHCPOptionsTable = "DHCP_Options" + +// DHCPOptions defines an object in DHCP_Options table +type DHCPOptions struct { + UUID string `ovsdb:"_uuid"` + Cidr string `ovsdb:"cidr"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Options map[string]string `ovsdb:"options"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/dns.go b/internal/server/network/openvswitch/schema/ovn-nb/dns.go new file mode 100644 index 00000000000..a2813821541 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/dns.go @@ -0,0 +1,13 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const DNSTable = "DNS" + +// DNS defines an object in DNS table +type DNS struct { + UUID string `ovsdb:"_uuid"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Records map[string]string `ovsdb:"records"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/forwarding_group.go b/internal/server/network/openvswitch/schema/ovn-nb/forwarding_group.go new file mode 100644 index 00000000000..398e1f1ad2a --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/forwarding_group.go @@ -0,0 +1,17 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const ForwardingGroupTable = "Forwarding_Group" + +// ForwardingGroup defines an object in Forwarding_Group table +type ForwardingGroup struct { + UUID string `ovsdb:"_uuid"` + ChildPort []string `ovsdb:"child_port"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Liveness bool `ovsdb:"liveness"` + Name string `ovsdb:"name"` + Vip string `ovsdb:"vip"` + Vmac string `ovsdb:"vmac"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/gateway_chassis.go b/internal/server/network/openvswitch/schema/ovn-nb/gateway_chassis.go new file mode 100644 index 00000000000..2d9191953f2 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/gateway_chassis.go @@ -0,0 +1,16 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const GatewayChassisTable = "Gateway_Chassis" + +// GatewayChassis defines an object in Gateway_Chassis table +type GatewayChassis struct { + UUID string `ovsdb:"_uuid"` + ChassisName string `ovsdb:"chassis_name"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Name string `ovsdb:"name"` + Options map[string]string `ovsdb:"options"` + Priority int `ovsdb:"priority"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/ha_chassis.go b/internal/server/network/openvswitch/schema/ovn-nb/ha_chassis.go new file mode 100644 index 00000000000..853354f7c0b --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/ha_chassis.go @@ -0,0 +1,14 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const HAChassisTable = "HA_Chassis" + +// HAChassis defines an object in HA_Chassis table +type HAChassis struct { + UUID string `ovsdb:"_uuid"` + ChassisName string `ovsdb:"chassis_name"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Priority int `ovsdb:"priority"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/ha_chassis_group.go b/internal/server/network/openvswitch/schema/ovn-nb/ha_chassis_group.go new file mode 100644 index 00000000000..4b962cf1a68 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/ha_chassis_group.go @@ -0,0 +1,14 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const HAChassisGroupTable = "HA_Chassis_Group" + +// HAChassisGroup defines an object in HA_Chassis_Group table +type HAChassisGroup struct { + UUID string `ovsdb:"_uuid"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + HaChassis []string `ovsdb:"ha_chassis"` + Name string `ovsdb:"name"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/load_balancer.go b/internal/server/network/openvswitch/schema/ovn-nb/load_balancer.go new file mode 100644 index 00000000000..dc2d65a7fbb --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/load_balancer.go @@ -0,0 +1,36 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const LoadBalancerTable = "Load_Balancer" + +type ( + LoadBalancerProtocol = string + LoadBalancerSelectionFields = string +) + +var ( + LoadBalancerProtocolTCP LoadBalancerProtocol = "tcp" + LoadBalancerProtocolUDP LoadBalancerProtocol = "udp" + LoadBalancerProtocolSCTP LoadBalancerProtocol = "sctp" + LoadBalancerSelectionFieldsEthSrc LoadBalancerSelectionFields = "eth_src" + LoadBalancerSelectionFieldsEthDst LoadBalancerSelectionFields = "eth_dst" + LoadBalancerSelectionFieldsIPSrc LoadBalancerSelectionFields = "ip_src" + LoadBalancerSelectionFieldsIPDst LoadBalancerSelectionFields = "ip_dst" + LoadBalancerSelectionFieldsTpSrc LoadBalancerSelectionFields = "tp_src" + LoadBalancerSelectionFieldsTpDst LoadBalancerSelectionFields = "tp_dst" +) + +// LoadBalancer defines an object in Load_Balancer table +type LoadBalancer struct { + UUID string `ovsdb:"_uuid"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + HealthCheck []string `ovsdb:"health_check"` + IPPortMappings map[string]string `ovsdb:"ip_port_mappings"` + Name string `ovsdb:"name"` + Options map[string]string `ovsdb:"options"` + Protocol *LoadBalancerProtocol `ovsdb:"protocol"` + SelectionFields []LoadBalancerSelectionFields `ovsdb:"selection_fields"` + Vips map[string]string `ovsdb:"vips"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/load_balancer_group.go b/internal/server/network/openvswitch/schema/ovn-nb/load_balancer_group.go new file mode 100644 index 00000000000..711a0ab7019 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/load_balancer_group.go @@ -0,0 +1,13 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const LoadBalancerGroupTable = "Load_Balancer_Group" + +// LoadBalancerGroup defines an object in Load_Balancer_Group table +type LoadBalancerGroup struct { + UUID string `ovsdb:"_uuid"` + LoadBalancer []string `ovsdb:"load_balancer"` + Name string `ovsdb:"name"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/load_balancer_health_check.go b/internal/server/network/openvswitch/schema/ovn-nb/load_balancer_health_check.go new file mode 100644 index 00000000000..43eb4761010 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/load_balancer_health_check.go @@ -0,0 +1,14 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const LoadBalancerHealthCheckTable = "Load_Balancer_Health_Check" + +// LoadBalancerHealthCheck defines an object in Load_Balancer_Health_Check table +type LoadBalancerHealthCheck struct { + UUID string `ovsdb:"_uuid"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Options map[string]string `ovsdb:"options"` + Vip string `ovsdb:"vip"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/logical_router.go b/internal/server/network/openvswitch/schema/ovn-nb/logical_router.go new file mode 100644 index 00000000000..fd2295f80b2 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/logical_router.go @@ -0,0 +1,22 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const LogicalRouterTable = "Logical_Router" + +// LogicalRouter defines an object in Logical_Router table +type LogicalRouter struct { + UUID string `ovsdb:"_uuid"` + Copp *string `ovsdb:"copp"` + Enabled *bool `ovsdb:"enabled"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + LoadBalancer []string `ovsdb:"load_balancer"` + LoadBalancerGroup []string `ovsdb:"load_balancer_group"` + Name string `ovsdb:"name"` + Nat []string `ovsdb:"nat"` + Options map[string]string `ovsdb:"options"` + Policies []string `ovsdb:"policies"` + Ports []string `ovsdb:"ports"` + StaticRoutes []string `ovsdb:"static_routes"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/logical_router_policy.go b/internal/server/network/openvswitch/schema/ovn-nb/logical_router_policy.go new file mode 100644 index 00000000000..e9f7925f089 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/logical_router_policy.go @@ -0,0 +1,28 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const LogicalRouterPolicyTable = "Logical_Router_Policy" + +type ( + LogicalRouterPolicyAction = string +) + +var ( + LogicalRouterPolicyActionAllow LogicalRouterPolicyAction = "allow" + LogicalRouterPolicyActionDrop LogicalRouterPolicyAction = "drop" + LogicalRouterPolicyActionReroute LogicalRouterPolicyAction = "reroute" +) + +// LogicalRouterPolicy defines an object in Logical_Router_Policy table +type LogicalRouterPolicy struct { + UUID string `ovsdb:"_uuid"` + Action LogicalRouterPolicyAction `ovsdb:"action"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Match string `ovsdb:"match"` + Nexthop *string `ovsdb:"nexthop"` + Nexthops []string `ovsdb:"nexthops"` + Options map[string]string `ovsdb:"options"` + Priority int `ovsdb:"priority"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/logical_router_port.go b/internal/server/network/openvswitch/schema/ovn-nb/logical_router_port.go new file mode 100644 index 00000000000..f45ffc85dc2 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/logical_router_port.go @@ -0,0 +1,22 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const LogicalRouterPortTable = "Logical_Router_Port" + +// LogicalRouterPort defines an object in Logical_Router_Port table +type LogicalRouterPort struct { + UUID string `ovsdb:"_uuid"` + Enabled *bool `ovsdb:"enabled"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + GatewayChassis []string `ovsdb:"gateway_chassis"` + HaChassisGroup *string `ovsdb:"ha_chassis_group"` + Ipv6Prefix []string `ovsdb:"ipv6_prefix"` + Ipv6RaConfigs map[string]string `ovsdb:"ipv6_ra_configs"` + MAC string `ovsdb:"mac"` + Name string `ovsdb:"name"` + Networks []string `ovsdb:"networks"` + Options map[string]string `ovsdb:"options"` + Peer *string `ovsdb:"peer"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/logical_router_static_route.go b/internal/server/network/openvswitch/schema/ovn-nb/logical_router_static_route.go new file mode 100644 index 00000000000..e0ef383229b --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/logical_router_static_route.go @@ -0,0 +1,28 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const LogicalRouterStaticRouteTable = "Logical_Router_Static_Route" + +type ( + LogicalRouterStaticRoutePolicy = string +) + +var ( + LogicalRouterStaticRoutePolicySrcIP LogicalRouterStaticRoutePolicy = "src-ip" + LogicalRouterStaticRoutePolicyDstIP LogicalRouterStaticRoutePolicy = "dst-ip" +) + +// LogicalRouterStaticRoute defines an object in Logical_Router_Static_Route table +type LogicalRouterStaticRoute struct { + UUID string `ovsdb:"_uuid"` + BFD *string `ovsdb:"bfd"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + IPPrefix string `ovsdb:"ip_prefix"` + Nexthop string `ovsdb:"nexthop"` + Options map[string]string `ovsdb:"options"` + OutputPort *string `ovsdb:"output_port"` + Policy *LogicalRouterStaticRoutePolicy `ovsdb:"policy"` + RouteTable string `ovsdb:"route_table"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/logical_switch.go b/internal/server/network/openvswitch/schema/ovn-nb/logical_switch.go new file mode 100644 index 00000000000..6f67289aa5f --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/logical_switch.go @@ -0,0 +1,22 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const LogicalSwitchTable = "Logical_Switch" + +// LogicalSwitch defines an object in Logical_Switch table +type LogicalSwitch struct { + UUID string `ovsdb:"_uuid"` + ACLs []string `ovsdb:"acls"` + Copp *string `ovsdb:"copp"` + DNSRecords []string `ovsdb:"dns_records"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + ForwardingGroups []string `ovsdb:"forwarding_groups"` + LoadBalancer []string `ovsdb:"load_balancer"` + LoadBalancerGroup []string `ovsdb:"load_balancer_group"` + Name string `ovsdb:"name"` + OtherConfig map[string]string `ovsdb:"other_config"` + Ports []string `ovsdb:"ports"` + QOSRules []string `ovsdb:"qos_rules"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/logical_switch_port.go b/internal/server/network/openvswitch/schema/ovn-nb/logical_switch_port.go new file mode 100644 index 00000000000..f66312deaed --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/logical_switch_port.go @@ -0,0 +1,27 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const LogicalSwitchPortTable = "Logical_Switch_Port" + +// LogicalSwitchPort defines an object in Logical_Switch_Port table +type LogicalSwitchPort struct { + UUID string `ovsdb:"_uuid"` + Addresses []string `ovsdb:"addresses"` + Dhcpv4Options *string `ovsdb:"dhcpv4_options"` + Dhcpv6Options *string `ovsdb:"dhcpv6_options"` + DynamicAddresses *string `ovsdb:"dynamic_addresses"` + Enabled *bool `ovsdb:"enabled"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + HaChassisGroup *string `ovsdb:"ha_chassis_group"` + MirrorRules []string `ovsdb:"mirror_rules"` + Name string `ovsdb:"name"` + Options map[string]string `ovsdb:"options"` + ParentName *string `ovsdb:"parent_name"` + PortSecurity []string `ovsdb:"port_security"` + Tag *int `ovsdb:"tag"` + TagRequest *int `ovsdb:"tag_request"` + Type string `ovsdb:"type"` + Up *bool `ovsdb:"up"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/meter.go b/internal/server/network/openvswitch/schema/ovn-nb/meter.go new file mode 100644 index 00000000000..236e9a02365 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/meter.go @@ -0,0 +1,25 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const MeterTable = "Meter" + +type ( + MeterUnit = string +) + +var ( + MeterUnitKbps MeterUnit = "kbps" + MeterUnitPktps MeterUnit = "pktps" +) + +// Meter defines an object in Meter table +type Meter struct { + UUID string `ovsdb:"_uuid"` + Bands []string `ovsdb:"bands"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Fair *bool `ovsdb:"fair"` + Name string `ovsdb:"name"` + Unit MeterUnit `ovsdb:"unit"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/meter_band.go b/internal/server/network/openvswitch/schema/ovn-nb/meter_band.go new file mode 100644 index 00000000000..4dbcf60990a --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/meter_band.go @@ -0,0 +1,23 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const MeterBandTable = "Meter_Band" + +type ( + MeterBandAction = string +) + +var ( + MeterBandActionDrop MeterBandAction = "drop" +) + +// MeterBand defines an object in Meter_Band table +type MeterBand struct { + UUID string `ovsdb:"_uuid"` + Action MeterBandAction `ovsdb:"action"` + BurstSize int `ovsdb:"burst_size"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Rate int `ovsdb:"rate"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/mirror.go b/internal/server/network/openvswitch/schema/ovn-nb/mirror.go new file mode 100644 index 00000000000..8d3551ca1b0 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/mirror.go @@ -0,0 +1,29 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const MirrorTable = "Mirror" + +type ( + MirrorFilter = string + MirrorType = string +) + +var ( + MirrorFilterFromLport MirrorFilter = "from-lport" + MirrorFilterToLport MirrorFilter = "to-lport" + MirrorTypeGre MirrorType = "gre" + MirrorTypeErspan MirrorType = "erspan" +) + +// Mirror defines an object in Mirror table +type Mirror struct { + UUID string `ovsdb:"_uuid"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Filter MirrorFilter `ovsdb:"filter"` + Index int `ovsdb:"index"` + Name string `ovsdb:"name"` + Sink string `ovsdb:"sink"` + Type MirrorType `ovsdb:"type"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/model.go b/internal/server/network/openvswitch/schema/ovn-nb/model.go new file mode 100644 index 00000000000..c5e30c2b4ef --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/model.go @@ -0,0 +1,1974 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +import ( + "encoding/json" + + "github.com/ovn-org/libovsdb/model" + "github.com/ovn-org/libovsdb/ovsdb" +) + +// FullDatabaseModel returns the DatabaseModel object to be used in libovsdb +func FullDatabaseModel() (model.ClientDBModel, error) { + return model.NewClientDBModel("OVN_Northbound", map[string]model.Model{ + "ACL": &ACL{}, + "Address_Set": &AddressSet{}, + "BFD": &BFD{}, + "Chassis_Template_Var": &ChassisTemplateVar{}, + "Connection": &Connection{}, + "Copp": &Copp{}, + "DHCP_Options": &DHCPOptions{}, + "DNS": &DNS{}, + "Forwarding_Group": &ForwardingGroup{}, + "Gateway_Chassis": &GatewayChassis{}, + "HA_Chassis": &HAChassis{}, + "HA_Chassis_Group": &HAChassisGroup{}, + "Load_Balancer": &LoadBalancer{}, + "Load_Balancer_Group": &LoadBalancerGroup{}, + "Load_Balancer_Health_Check": &LoadBalancerHealthCheck{}, + "Logical_Router": &LogicalRouter{}, + "Logical_Router_Policy": &LogicalRouterPolicy{}, + "Logical_Router_Port": &LogicalRouterPort{}, + "Logical_Router_Static_Route": &LogicalRouterStaticRoute{}, + "Logical_Switch": &LogicalSwitch{}, + "Logical_Switch_Port": &LogicalSwitchPort{}, + "Meter": &Meter{}, + "Meter_Band": &MeterBand{}, + "Mirror": &Mirror{}, + "NAT": &NAT{}, + "NB_Global": &NBGlobal{}, + "Port_Group": &PortGroup{}, + "QoS": &QoS{}, + "SSL": &SSL{}, + "Static_MAC_Binding": &StaticMACBinding{}, + }) +} + +var schema = `{ + "name": "OVN_Northbound", + "version": "7.0.0", + "tables": { + "ACL": { + "columns": { + "action": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "allow", + "allow-related", + "allow-stateless", + "drop", + "reject" + ] + ] + } + } + }, + "direction": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "from-lport", + "to-lport" + ] + ] + } + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "label": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 4294967295 + } + } + }, + "log": { + "type": "boolean" + }, + "match": { + "type": "string" + }, + "meter": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "name": { + "type": { + "key": { + "type": "string", + "minLength": 63, + "maxLength": 63 + }, + "min": 0, + "max": 1 + } + }, + "options": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "priority": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 32767 + } + } + }, + "severity": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "alert", + "warning", + "notice", + "info", + "debug" + ] + ] + }, + "min": 0, + "max": 1 + } + } + } + }, + "Address_Set": { + "columns": { + "addresses": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "name": { + "type": "string" + } + }, + "indexes": [ + [ + "name" + ] + ] + }, + "BFD": { + "columns": { + "detect_mult": { + "type": { + "key": { + "type": "integer", + "minInteger": 1 + }, + "min": 0, + "max": 1 + } + }, + "dst_ip": { + "type": "string" + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "logical_port": { + "type": "string" + }, + "min_rx": { + "type": { + "key": { + "type": "integer" + }, + "min": 0, + "max": 1 + } + }, + "min_tx": { + "type": { + "key": { + "type": "integer", + "minInteger": 1 + }, + "min": 0, + "max": 1 + } + }, + "options": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "status": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "down", + "init", + "up", + "admin_down" + ] + ] + }, + "min": 0, + "max": 1 + } + } + }, + "indexes": [ + [ + "logical_port", + "dst_ip" + ] + ] + }, + "Chassis_Template_Var": { + "columns": { + "chassis": { + "type": "string" + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "variables": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + } + }, + "indexes": [ + [ + "chassis" + ] + ] + }, + "Connection": { + "columns": { + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "inactivity_probe": { + "type": { + "key": { + "type": "integer" + }, + "min": 0, + "max": 1 + } + }, + "is_connected": { + "type": "boolean", + "ephemeral": true + }, + "max_backoff": { + "type": { + "key": { + "type": "integer", + "minInteger": 1000 + }, + "min": 0, + "max": 1 + } + }, + "other_config": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "status": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + }, + "ephemeral": true + }, + "target": { + "type": "string" + } + }, + "indexes": [ + [ + "target" + ] + ] + }, + "Copp": { + "columns": { + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "meters": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "name": { + "type": "string" + } + }, + "indexes": [ + [ + "name" + ] + ] + }, + "DHCP_Options": { + "columns": { + "cidr": { + "type": "string" + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "options": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + } + } + }, + "DNS": { + "columns": { + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "records": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + } + } + }, + "Forwarding_Group": { + "columns": { + "child_port": { + "type": { + "key": { + "type": "string" + }, + "min": 1, + "max": "unlimited" + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "liveness": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "vip": { + "type": "string" + }, + "vmac": { + "type": "string" + } + } + }, + "Gateway_Chassis": { + "columns": { + "chassis_name": { + "type": "string" + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "name": { + "type": "string" + }, + "options": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "priority": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 32767 + } + } + } + }, + "indexes": [ + [ + "name" + ] + ] + }, + "HA_Chassis": { + "columns": { + "chassis_name": { + "type": "string" + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "priority": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 32767 + } + } + } + } + }, + "HA_Chassis_Group": { + "columns": { + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "ha_chassis": { + "type": { + "key": { + "type": "uuid", + "refTable": "HA_Chassis", + "refType": "strong" + }, + "min": 0, + "max": "unlimited" + } + }, + "name": { + "type": "string" + } + }, + "indexes": [ + [ + "name" + ] + ] + }, + "Load_Balancer": { + "columns": { + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "health_check": { + "type": { + "key": { + "type": "uuid", + "refTable": "Load_Balancer_Health_Check", + "refType": "strong" + }, + "min": 0, + "max": "unlimited" + } + }, + "ip_port_mappings": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "name": { + "type": "string" + }, + "options": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "protocol": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "tcp", + "udp", + "sctp" + ] + ] + }, + "min": 0, + "max": 1 + } + }, + "selection_fields": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "eth_src", + "eth_dst", + "ip_src", + "ip_dst", + "tp_src", + "tp_dst" + ] + ] + }, + "min": 0, + "max": "unlimited" + } + }, + "vips": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + } + } + }, + "Load_Balancer_Group": { + "columns": { + "load_balancer": { + "type": { + "key": { + "type": "uuid", + "refTable": "Load_Balancer", + "refType": "weak" + }, + "min": 0, + "max": "unlimited" + } + }, + "name": { + "type": "string" + } + }, + "indexes": [ + [ + "name" + ] + ] + }, + "Load_Balancer_Health_Check": { + "columns": { + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "options": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "vip": { + "type": "string" + } + } + }, + "Logical_Router": { + "columns": { + "copp": { + "type": { + "key": { + "type": "uuid", + "refTable": "Copp", + "refType": "weak" + }, + "min": 0, + "max": 1 + } + }, + "enabled": { + "type": { + "key": { + "type": "boolean" + }, + "min": 0, + "max": 1 + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "load_balancer": { + "type": { + "key": { + "type": "uuid", + "refTable": "Load_Balancer", + "refType": "weak" + }, + "min": 0, + "max": "unlimited" + } + }, + "load_balancer_group": { + "type": { + "key": { + "type": "uuid", + "refTable": "Load_Balancer_Group" + }, + "min": 0, + "max": "unlimited" + } + }, + "name": { + "type": "string" + }, + "nat": { + "type": { + "key": { + "type": "uuid", + "refTable": "NAT", + "refType": "strong" + }, + "min": 0, + "max": "unlimited" + } + }, + "options": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "policies": { + "type": { + "key": { + "type": "uuid", + "refTable": "Logical_Router_Policy", + "refType": "strong" + }, + "min": 0, + "max": "unlimited" + } + }, + "ports": { + "type": { + "key": { + "type": "uuid", + "refTable": "Logical_Router_Port", + "refType": "strong" + }, + "min": 0, + "max": "unlimited" + } + }, + "static_routes": { + "type": { + "key": { + "type": "uuid", + "refTable": "Logical_Router_Static_Route", + "refType": "strong" + }, + "min": 0, + "max": "unlimited" + } + } + } + }, + "Logical_Router_Policy": { + "columns": { + "action": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "allow", + "drop", + "reroute" + ] + ] + } + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "match": { + "type": "string" + }, + "nexthop": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "nexthops": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "options": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "priority": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 32767 + } + } + } + } + }, + "Logical_Router_Port": { + "columns": { + "enabled": { + "type": { + "key": { + "type": "boolean" + }, + "min": 0, + "max": 1 + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "gateway_chassis": { + "type": { + "key": { + "type": "uuid", + "refTable": "Gateway_Chassis", + "refType": "strong" + }, + "min": 0, + "max": "unlimited" + } + }, + "ha_chassis_group": { + "type": { + "key": { + "type": "uuid", + "refTable": "HA_Chassis_Group", + "refType": "strong" + }, + "min": 0, + "max": 1 + } + }, + "ipv6_prefix": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "ipv6_ra_configs": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "mac": { + "type": "string" + }, + "name": { + "type": "string" + }, + "networks": { + "type": { + "key": { + "type": "string" + }, + "min": 1, + "max": "unlimited" + } + }, + "options": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "peer": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + } + }, + "indexes": [ + [ + "name" + ] + ] + }, + "Logical_Router_Static_Route": { + "columns": { + "bfd": { + "type": { + "key": { + "type": "uuid", + "refTable": "BFD", + "refType": "weak" + }, + "min": 0, + "max": 1 + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "ip_prefix": { + "type": "string" + }, + "nexthop": { + "type": "string" + }, + "options": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "output_port": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "policy": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "src-ip", + "dst-ip" + ] + ] + }, + "min": 0, + "max": 1 + } + }, + "route_table": { + "type": "string" + } + } + }, + "Logical_Switch": { + "columns": { + "acls": { + "type": { + "key": { + "type": "uuid", + "refTable": "ACL", + "refType": "strong" + }, + "min": 0, + "max": "unlimited" + } + }, + "copp": { + "type": { + "key": { + "type": "uuid", + "refTable": "Copp", + "refType": "weak" + }, + "min": 0, + "max": 1 + } + }, + "dns_records": { + "type": { + "key": { + "type": "uuid", + "refTable": "DNS", + "refType": "weak" + }, + "min": 0, + "max": "unlimited" + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "forwarding_groups": { + "type": { + "key": { + "type": "uuid", + "refTable": "Forwarding_Group", + "refType": "strong" + }, + "min": 0, + "max": "unlimited" + } + }, + "load_balancer": { + "type": { + "key": { + "type": "uuid", + "refTable": "Load_Balancer", + "refType": "weak" + }, + "min": 0, + "max": "unlimited" + } + }, + "load_balancer_group": { + "type": { + "key": { + "type": "uuid", + "refTable": "Load_Balancer_Group" + }, + "min": 0, + "max": "unlimited" + } + }, + "name": { + "type": "string" + }, + "other_config": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "ports": { + "type": { + "key": { + "type": "uuid", + "refTable": "Logical_Switch_Port", + "refType": "strong" + }, + "min": 0, + "max": "unlimited" + } + }, + "qos_rules": { + "type": { + "key": { + "type": "uuid", + "refTable": "QoS", + "refType": "strong" + }, + "min": 0, + "max": "unlimited" + } + } + } + }, + "Logical_Switch_Port": { + "columns": { + "addresses": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "dhcpv4_options": { + "type": { + "key": { + "type": "uuid", + "refTable": "DHCP_Options", + "refType": "weak" + }, + "min": 0, + "max": 1 + } + }, + "dhcpv6_options": { + "type": { + "key": { + "type": "uuid", + "refTable": "DHCP_Options", + "refType": "weak" + }, + "min": 0, + "max": 1 + } + }, + "dynamic_addresses": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "enabled": { + "type": { + "key": { + "type": "boolean" + }, + "min": 0, + "max": 1 + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "ha_chassis_group": { + "type": { + "key": { + "type": "uuid", + "refTable": "HA_Chassis_Group", + "refType": "strong" + }, + "min": 0, + "max": 1 + } + }, + "mirror_rules": { + "type": { + "key": { + "type": "uuid", + "refTable": "Mirror", + "refType": "weak" + }, + "min": 0, + "max": "unlimited" + } + }, + "name": { + "type": "string" + }, + "options": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "parent_name": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "port_security": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "tag": { + "type": { + "key": { + "type": "integer", + "minInteger": 1, + "maxInteger": 4095 + }, + "min": 0, + "max": 1 + } + }, + "tag_request": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 4095 + }, + "min": 0, + "max": 1 + } + }, + "type": { + "type": "string" + }, + "up": { + "type": { + "key": { + "type": "boolean" + }, + "min": 0, + "max": 1 + } + } + }, + "indexes": [ + [ + "name" + ] + ] + }, + "Meter": { + "columns": { + "bands": { + "type": { + "key": { + "type": "uuid", + "refTable": "Meter_Band", + "refType": "strong" + }, + "min": 1, + "max": "unlimited" + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "fair": { + "type": { + "key": { + "type": "boolean" + }, + "min": 0, + "max": 1 + } + }, + "name": { + "type": "string" + }, + "unit": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "kbps", + "pktps" + ] + ] + } + } + } + }, + "indexes": [ + [ + "name" + ] + ] + }, + "Meter_Band": { + "columns": { + "action": { + "type": { + "key": { + "type": "string", + "enum": "drop" + } + } + }, + "burst_size": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 4294967295 + } + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "rate": { + "type": { + "key": { + "type": "integer", + "minInteger": 1, + "maxInteger": 4294967295 + } + } + } + } + }, + "Mirror": { + "columns": { + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "filter": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "from-lport", + "to-lport" + ] + ] + } + } + }, + "index": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "sink": { + "type": "string" + }, + "type": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "gre", + "erspan" + ] + ] + } + } + } + }, + "indexes": [ + [ + "name" + ] + ] + }, + "NAT": { + "columns": { + "allowed_ext_ips": { + "type": { + "key": { + "type": "uuid", + "refTable": "Address_Set", + "refType": "strong" + }, + "min": 0, + "max": 1 + } + }, + "exempted_ext_ips": { + "type": { + "key": { + "type": "uuid", + "refTable": "Address_Set", + "refType": "strong" + }, + "min": 0, + "max": 1 + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "external_ip": { + "type": "string" + }, + "external_mac": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "external_port_range": { + "type": "string" + }, + "gateway_port": { + "type": { + "key": { + "type": "uuid", + "refTable": "Logical_Router_Port", + "refType": "weak" + }, + "min": 0, + "max": 1 + } + }, + "logical_ip": { + "type": "string" + }, + "logical_port": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "options": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "type": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "dnat", + "snat", + "dnat_and_snat" + ] + ] + } + } + } + } + }, + "NB_Global": { + "columns": { + "connections": { + "type": { + "key": { + "type": "uuid", + "refTable": "Connection" + }, + "min": 0, + "max": "unlimited" + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "hv_cfg": { + "type": "integer" + }, + "hv_cfg_timestamp": { + "type": "integer" + }, + "ipsec": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "nb_cfg": { + "type": "integer" + }, + "nb_cfg_timestamp": { + "type": "integer" + }, + "options": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "sb_cfg": { + "type": "integer" + }, + "sb_cfg_timestamp": { + "type": "integer" + }, + "ssl": { + "type": { + "key": { + "type": "uuid", + "refTable": "SSL" + }, + "min": 0, + "max": 1 + } + } + } + }, + "Port_Group": { + "columns": { + "acls": { + "type": { + "key": { + "type": "uuid", + "refTable": "ACL", + "refType": "strong" + }, + "min": 0, + "max": "unlimited" + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "name": { + "type": "string" + }, + "ports": { + "type": { + "key": { + "type": "uuid", + "refTable": "Logical_Switch_Port", + "refType": "weak" + }, + "min": 0, + "max": "unlimited" + } + } + }, + "indexes": [ + [ + "name" + ] + ] + }, + "QoS": { + "columns": { + "action": { + "type": { + "key": { + "type": "string", + "enum": "dscp" + }, + "value": { + "type": "integer", + "minInteger": 0, + "maxInteger": 63 + }, + "min": 0, + "max": "unlimited" + } + }, + "bandwidth": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "rate", + "burst" + ] + ] + }, + "value": { + "type": "integer", + "minInteger": 1, + "maxInteger": 4294967295 + }, + "min": 0, + "max": "unlimited" + } + }, + "direction": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "from-lport", + "to-lport" + ] + ] + } + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "match": { + "type": "string" + }, + "priority": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 32767 + } + } + } + } + }, + "SSL": { + "columns": { + "bootstrap_ca_cert": { + "type": "boolean" + }, + "ca_cert": { + "type": "string" + }, + "certificate": { + "type": "string" + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "private_key": { + "type": "string" + }, + "ssl_ciphers": { + "type": "string" + }, + "ssl_protocols": { + "type": "string" + } + } + }, + "Static_MAC_Binding": { + "columns": { + "ip": { + "type": "string" + }, + "logical_port": { + "type": "string" + }, + "mac": { + "type": "string" + }, + "override_dynamic_mac": { + "type": "boolean" + } + }, + "indexes": [ + [ + "logical_port", + "ip" + ] + ] + } + } +}` + +func Schema() ovsdb.DatabaseSchema { + var s ovsdb.DatabaseSchema + err := json.Unmarshal([]byte(schema), &s) + if err != nil { + panic(err) + } + return s +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/nat.go b/internal/server/network/openvswitch/schema/ovn-nb/nat.go new file mode 100644 index 00000000000..9ee78a1e8e0 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/nat.go @@ -0,0 +1,32 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const NATTable = "NAT" + +type ( + NATType = string +) + +var ( + NATTypeDNAT NATType = "dnat" + NATTypeSNAT NATType = "snat" + NATTypeDNATAndSNAT NATType = "dnat_and_snat" +) + +// NAT defines an object in NAT table +type NAT struct { + UUID string `ovsdb:"_uuid"` + AllowedExtIPs *string `ovsdb:"allowed_ext_ips"` + ExemptedExtIPs *string `ovsdb:"exempted_ext_ips"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + ExternalIP string `ovsdb:"external_ip"` + ExternalMAC *string `ovsdb:"external_mac"` + ExternalPortRange string `ovsdb:"external_port_range"` + GatewayPort *string `ovsdb:"gateway_port"` + LogicalIP string `ovsdb:"logical_ip"` + LogicalPort *string `ovsdb:"logical_port"` + Options map[string]string `ovsdb:"options"` + Type NATType `ovsdb:"type"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/nb_global.go b/internal/server/network/openvswitch/schema/ovn-nb/nb_global.go new file mode 100644 index 00000000000..8cb6af71aad --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/nb_global.go @@ -0,0 +1,23 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const NBGlobalTable = "NB_Global" + +// NBGlobal defines an object in NB_Global table +type NBGlobal struct { + UUID string `ovsdb:"_uuid"` + Connections []string `ovsdb:"connections"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + HvCfg int `ovsdb:"hv_cfg"` + HvCfgTimestamp int `ovsdb:"hv_cfg_timestamp"` + Ipsec bool `ovsdb:"ipsec"` + Name string `ovsdb:"name"` + NbCfg int `ovsdb:"nb_cfg"` + NbCfgTimestamp int `ovsdb:"nb_cfg_timestamp"` + Options map[string]string `ovsdb:"options"` + SbCfg int `ovsdb:"sb_cfg"` + SbCfgTimestamp int `ovsdb:"sb_cfg_timestamp"` + SSL *string `ovsdb:"ssl"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/port_group.go b/internal/server/network/openvswitch/schema/ovn-nb/port_group.go new file mode 100644 index 00000000000..989c747087a --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/port_group.go @@ -0,0 +1,15 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const PortGroupTable = "Port_Group" + +// PortGroup defines an object in Port_Group table +type PortGroup struct { + UUID string `ovsdb:"_uuid"` + ACLs []string `ovsdb:"acls"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Name string `ovsdb:"name"` + Ports []string `ovsdb:"ports"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/qos.go b/internal/server/network/openvswitch/schema/ovn-nb/qos.go new file mode 100644 index 00000000000..dffa414c26e --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/qos.go @@ -0,0 +1,31 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const QoSTable = "QoS" + +type ( + QoSAction = string + QoSBandwidth = string + QoSDirection = string +) + +var ( + QoSActionDSCP QoSAction = "dscp" + QoSBandwidthRate QoSBandwidth = "rate" + QoSBandwidthBurst QoSBandwidth = "burst" + QoSDirectionFromLport QoSDirection = "from-lport" + QoSDirectionToLport QoSDirection = "to-lport" +) + +// QoS defines an object in QoS table +type QoS struct { + UUID string `ovsdb:"_uuid"` + Action map[string]int `ovsdb:"action"` + Bandwidth map[string]int `ovsdb:"bandwidth"` + Direction QoSDirection `ovsdb:"direction"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Match string `ovsdb:"match"` + Priority int `ovsdb:"priority"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/ssl.go b/internal/server/network/openvswitch/schema/ovn-nb/ssl.go new file mode 100644 index 00000000000..2cfd4305eff --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/ssl.go @@ -0,0 +1,18 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const SSLTable = "SSL" + +// SSL defines an object in SSL table +type SSL struct { + UUID string `ovsdb:"_uuid"` + BootstrapCaCert bool `ovsdb:"bootstrap_ca_cert"` + CaCert string `ovsdb:"ca_cert"` + Certificate string `ovsdb:"certificate"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + PrivateKey string `ovsdb:"private_key"` + SSLCiphers string `ovsdb:"ssl_ciphers"` + SSLProtocols string `ovsdb:"ssl_protocols"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-nb/static_mac_binding.go b/internal/server/network/openvswitch/schema/ovn-nb/static_mac_binding.go new file mode 100644 index 00000000000..04c87abc7fe --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-nb/static_mac_binding.go @@ -0,0 +1,15 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const StaticMACBindingTable = "Static_MAC_Binding" + +// StaticMACBinding defines an object in Static_MAC_Binding table +type StaticMACBinding struct { + UUID string `ovsdb:"_uuid"` + IP string `ovsdb:"ip"` + LogicalPort string `ovsdb:"logical_port"` + MAC string `ovsdb:"mac"` + OverrideDynamicMAC bool `ovsdb:"override_dynamic_mac"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/address_set.go b/internal/server/network/openvswitch/schema/ovn-sb/address_set.go new file mode 100644 index 00000000000..c9f4f204a1c --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/address_set.go @@ -0,0 +1,13 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const AddressSetTable = "Address_Set" + +// AddressSet defines an object in Address_Set table +type AddressSet struct { + UUID string `ovsdb:"_uuid"` + Addresses []string `ovsdb:"addresses"` + Name string `ovsdb:"name"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/bfd.go b/internal/server/network/openvswitch/schema/ovn-sb/bfd.go new file mode 100644 index 00000000000..d1ed175a013 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/bfd.go @@ -0,0 +1,32 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const BFDTable = "BFD" + +type ( + BFDStatus = string +) + +var ( + BFDStatusDown BFDStatus = "down" + BFDStatusInit BFDStatus = "init" + BFDStatusUp BFDStatus = "up" + BFDStatusAdminDown BFDStatus = "admin_down" +) + +// BFD defines an object in BFD table +type BFD struct { + UUID string `ovsdb:"_uuid"` + DetectMult int `ovsdb:"detect_mult"` + Disc int `ovsdb:"disc"` + DstIP string `ovsdb:"dst_ip"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + LogicalPort string `ovsdb:"logical_port"` + MinRx int `ovsdb:"min_rx"` + MinTx int `ovsdb:"min_tx"` + Options map[string]string `ovsdb:"options"` + SrcPort int `ovsdb:"src_port"` + Status BFDStatus `ovsdb:"status"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/chassis.go b/internal/server/network/openvswitch/schema/ovn-sb/chassis.go new file mode 100644 index 00000000000..f49dd11b6c9 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/chassis.go @@ -0,0 +1,19 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const ChassisTable = "Chassis" + +// Chassis defines an object in Chassis table +type Chassis struct { + UUID string `ovsdb:"_uuid"` + Encaps []string `ovsdb:"encaps"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Hostname string `ovsdb:"hostname"` + Name string `ovsdb:"name"` + NbCfg int `ovsdb:"nb_cfg"` + OtherConfig map[string]string `ovsdb:"other_config"` + TransportZones []string `ovsdb:"transport_zones"` + VtepLogicalSwitches []string `ovsdb:"vtep_logical_switches"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/chassis_private.go b/internal/server/network/openvswitch/schema/ovn-sb/chassis_private.go new file mode 100644 index 00000000000..8faa22964b0 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/chassis_private.go @@ -0,0 +1,16 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const ChassisPrivateTable = "Chassis_Private" + +// ChassisPrivate defines an object in Chassis_Private table +type ChassisPrivate struct { + UUID string `ovsdb:"_uuid"` + Chassis *string `ovsdb:"chassis"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Name string `ovsdb:"name"` + NbCfg int `ovsdb:"nb_cfg"` + NbCfgTimestamp int `ovsdb:"nb_cfg_timestamp"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/chassis_template_var.go b/internal/server/network/openvswitch/schema/ovn-sb/chassis_template_var.go new file mode 100644 index 00000000000..3866be46f23 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/chassis_template_var.go @@ -0,0 +1,13 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const ChassisTemplateVarTable = "Chassis_Template_Var" + +// ChassisTemplateVar defines an object in Chassis_Template_Var table +type ChassisTemplateVar struct { + UUID string `ovsdb:"_uuid"` + Chassis string `ovsdb:"chassis"` + Variables map[string]string `ovsdb:"variables"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/connection.go b/internal/server/network/openvswitch/schema/ovn-sb/connection.go new file mode 100644 index 00000000000..9d025f32a4e --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/connection.go @@ -0,0 +1,20 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const ConnectionTable = "Connection" + +// Connection defines an object in Connection table +type Connection struct { + UUID string `ovsdb:"_uuid"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + InactivityProbe *int `ovsdb:"inactivity_probe"` + IsConnected bool `ovsdb:"is_connected"` + MaxBackoff *int `ovsdb:"max_backoff"` + OtherConfig map[string]string `ovsdb:"other_config"` + ReadOnly bool `ovsdb:"read_only"` + Role string `ovsdb:"role"` + Status map[string]string `ovsdb:"status"` + Target string `ovsdb:"target"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/controller_event.go b/internal/server/network/openvswitch/schema/ovn-sb/controller_event.go new file mode 100644 index 00000000000..f5f6a0b85af --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/controller_event.go @@ -0,0 +1,23 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const ControllerEventTable = "Controller_Event" + +type ( + ControllerEventEventType = string +) + +var ( + ControllerEventEventTypeEmptyLbBackends ControllerEventEventType = "empty_lb_backends" +) + +// ControllerEvent defines an object in Controller_Event table +type ControllerEvent struct { + UUID string `ovsdb:"_uuid"` + Chassis *string `ovsdb:"chassis"` + EventInfo map[string]string `ovsdb:"event_info"` + EventType ControllerEventEventType `ovsdb:"event_type"` + SeqNum int `ovsdb:"seq_num"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/datapath_binding.go b/internal/server/network/openvswitch/schema/ovn-sb/datapath_binding.go new file mode 100644 index 00000000000..ead76e25341 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/datapath_binding.go @@ -0,0 +1,14 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const DatapathBindingTable = "Datapath_Binding" + +// DatapathBinding defines an object in Datapath_Binding table +type DatapathBinding struct { + UUID string `ovsdb:"_uuid"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + LoadBalancers []string `ovsdb:"load_balancers"` + TunnelKey int `ovsdb:"tunnel_key"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/dhcp_options.go b/internal/server/network/openvswitch/schema/ovn-sb/dhcp_options.go new file mode 100644 index 00000000000..50b1c26a1ad --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/dhcp_options.go @@ -0,0 +1,30 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const DHCPOptionsTable = "DHCP_Options" + +type ( + DHCPOptionsType = string +) + +var ( + DHCPOptionsTypeBool DHCPOptionsType = "bool" + DHCPOptionsTypeUint8 DHCPOptionsType = "uint8" + DHCPOptionsTypeUint16 DHCPOptionsType = "uint16" + DHCPOptionsTypeUint32 DHCPOptionsType = "uint32" + DHCPOptionsTypeIpv4 DHCPOptionsType = "ipv4" + DHCPOptionsTypeStaticRoutes DHCPOptionsType = "static_routes" + DHCPOptionsTypeStr DHCPOptionsType = "str" + DHCPOptionsTypeHostID DHCPOptionsType = "host_id" + DHCPOptionsTypeDomains DHCPOptionsType = "domains" +) + +// DHCPOptions defines an object in DHCP_Options table +type DHCPOptions struct { + UUID string `ovsdb:"_uuid"` + Code int `ovsdb:"code"` + Name string `ovsdb:"name"` + Type DHCPOptionsType `ovsdb:"type"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/dhcpv6_options.go b/internal/server/network/openvswitch/schema/ovn-sb/dhcpv6_options.go new file mode 100644 index 00000000000..08a4763f3da --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/dhcpv6_options.go @@ -0,0 +1,24 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const DHCPv6OptionsTable = "DHCPv6_Options" + +type ( + DHCPv6OptionsType = string +) + +var ( + DHCPv6OptionsTypeIpv6 DHCPv6OptionsType = "ipv6" + DHCPv6OptionsTypeStr DHCPv6OptionsType = "str" + DHCPv6OptionsTypeMAC DHCPv6OptionsType = "mac" +) + +// DHCPv6Options defines an object in DHCPv6_Options table +type DHCPv6Options struct { + UUID string `ovsdb:"_uuid"` + Code int `ovsdb:"code"` + Name string `ovsdb:"name"` + Type DHCPv6OptionsType `ovsdb:"type"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/dns.go b/internal/server/network/openvswitch/schema/ovn-sb/dns.go new file mode 100644 index 00000000000..82c18f9aa4c --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/dns.go @@ -0,0 +1,14 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const DNSTable = "DNS" + +// DNS defines an object in DNS table +type DNS struct { + UUID string `ovsdb:"_uuid"` + Datapaths []string `ovsdb:"datapaths"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Records map[string]string `ovsdb:"records"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/encap.go b/internal/server/network/openvswitch/schema/ovn-sb/encap.go new file mode 100644 index 00000000000..8d2a1873529 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/encap.go @@ -0,0 +1,25 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const EncapTable = "Encap" + +type ( + EncapType = string +) + +var ( + EncapTypeGeneve EncapType = "geneve" + EncapTypeSTT EncapType = "stt" + EncapTypeVxlan EncapType = "vxlan" +) + +// Encap defines an object in Encap table +type Encap struct { + UUID string `ovsdb:"_uuid"` + ChassisName string `ovsdb:"chassis_name"` + IP string `ovsdb:"ip"` + Options map[string]string `ovsdb:"options"` + Type EncapType `ovsdb:"type"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/fdb.go b/internal/server/network/openvswitch/schema/ovn-sb/fdb.go new file mode 100644 index 00000000000..fd08635eebb --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/fdb.go @@ -0,0 +1,14 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const FDBTable = "FDB" + +// FDB defines an object in FDB table +type FDB struct { + UUID string `ovsdb:"_uuid"` + DpKey int `ovsdb:"dp_key"` + MAC string `ovsdb:"mac"` + PortKey int `ovsdb:"port_key"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/gateway_chassis.go b/internal/server/network/openvswitch/schema/ovn-sb/gateway_chassis.go new file mode 100644 index 00000000000..a7eca3cf267 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/gateway_chassis.go @@ -0,0 +1,16 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const GatewayChassisTable = "Gateway_Chassis" + +// GatewayChassis defines an object in Gateway_Chassis table +type GatewayChassis struct { + UUID string `ovsdb:"_uuid"` + Chassis *string `ovsdb:"chassis"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Name string `ovsdb:"name"` + Options map[string]string `ovsdb:"options"` + Priority int `ovsdb:"priority"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/ha_chassis.go b/internal/server/network/openvswitch/schema/ovn-sb/ha_chassis.go new file mode 100644 index 00000000000..6c85ac8945c --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/ha_chassis.go @@ -0,0 +1,14 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const HAChassisTable = "HA_Chassis" + +// HAChassis defines an object in HA_Chassis table +type HAChassis struct { + UUID string `ovsdb:"_uuid"` + Chassis *string `ovsdb:"chassis"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Priority int `ovsdb:"priority"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/ha_chassis_group.go b/internal/server/network/openvswitch/schema/ovn-sb/ha_chassis_group.go new file mode 100644 index 00000000000..184074bd055 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/ha_chassis_group.go @@ -0,0 +1,15 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const HAChassisGroupTable = "HA_Chassis_Group" + +// HAChassisGroup defines an object in HA_Chassis_Group table +type HAChassisGroup struct { + UUID string `ovsdb:"_uuid"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + HaChassis []string `ovsdb:"ha_chassis"` + Name string `ovsdb:"name"` + RefChassis []string `ovsdb:"ref_chassis"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/igmp_group.go b/internal/server/network/openvswitch/schema/ovn-sb/igmp_group.go new file mode 100644 index 00000000000..8fbf6da2e52 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/igmp_group.go @@ -0,0 +1,15 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const IGMPGroupTable = "IGMP_Group" + +// IGMPGroup defines an object in IGMP_Group table +type IGMPGroup struct { + UUID string `ovsdb:"_uuid"` + Address string `ovsdb:"address"` + Chassis *string `ovsdb:"chassis"` + Datapath *string `ovsdb:"datapath"` + Ports []string `ovsdb:"ports"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/ip_multicast.go b/internal/server/network/openvswitch/schema/ovn-sb/ip_multicast.go new file mode 100644 index 00000000000..34136b69ef9 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/ip_multicast.go @@ -0,0 +1,22 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const IPMulticastTable = "IP_Multicast" + +// IPMulticast defines an object in IP_Multicast table +type IPMulticast struct { + UUID string `ovsdb:"_uuid"` + Datapath string `ovsdb:"datapath"` + Enabled *bool `ovsdb:"enabled"` + EthSrc string `ovsdb:"eth_src"` + IdleTimeout *int `ovsdb:"idle_timeout"` + Ip4Src string `ovsdb:"ip4_src"` + Ip6Src string `ovsdb:"ip6_src"` + Querier *bool `ovsdb:"querier"` + QueryInterval *int `ovsdb:"query_interval"` + QueryMaxResp *int `ovsdb:"query_max_resp"` + SeqNo int `ovsdb:"seq_no"` + TableSize *int `ovsdb:"table_size"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/load_balancer.go b/internal/server/network/openvswitch/schema/ovn-sb/load_balancer.go new file mode 100644 index 00000000000..829c10d2ed9 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/load_balancer.go @@ -0,0 +1,28 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const LoadBalancerTable = "Load_Balancer" + +type ( + LoadBalancerProtocol = string +) + +var ( + LoadBalancerProtocolTCP LoadBalancerProtocol = "tcp" + LoadBalancerProtocolUDP LoadBalancerProtocol = "udp" + LoadBalancerProtocolSCTP LoadBalancerProtocol = "sctp" +) + +// LoadBalancer defines an object in Load_Balancer table +type LoadBalancer struct { + UUID string `ovsdb:"_uuid"` + DatapathGroup *string `ovsdb:"datapath_group"` + Datapaths []string `ovsdb:"datapaths"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Name string `ovsdb:"name"` + Options map[string]string `ovsdb:"options"` + Protocol *LoadBalancerProtocol `ovsdb:"protocol"` + Vips map[string]string `ovsdb:"vips"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/logical_dp_group.go b/internal/server/network/openvswitch/schema/ovn-sb/logical_dp_group.go new file mode 100644 index 00000000000..343fae04c89 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/logical_dp_group.go @@ -0,0 +1,12 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const LogicalDPGroupTable = "Logical_DP_Group" + +// LogicalDPGroup defines an object in Logical_DP_Group table +type LogicalDPGroup struct { + UUID string `ovsdb:"_uuid"` + Datapaths []string `ovsdb:"datapaths"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/logical_flow.go b/internal/server/network/openvswitch/schema/ovn-sb/logical_flow.go new file mode 100644 index 00000000000..4e3bdfa62d7 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/logical_flow.go @@ -0,0 +1,30 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const LogicalFlowTable = "Logical_Flow" + +type ( + LogicalFlowPipeline = string +) + +var ( + LogicalFlowPipelineIngress LogicalFlowPipeline = "ingress" + LogicalFlowPipelineEgress LogicalFlowPipeline = "egress" +) + +// LogicalFlow defines an object in Logical_Flow table +type LogicalFlow struct { + UUID string `ovsdb:"_uuid"` + Actions string `ovsdb:"actions"` + ControllerMeter *string `ovsdb:"controller_meter"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + LogicalDatapath *string `ovsdb:"logical_datapath"` + LogicalDpGroup *string `ovsdb:"logical_dp_group"` + Match string `ovsdb:"match"` + Pipeline LogicalFlowPipeline `ovsdb:"pipeline"` + Priority int `ovsdb:"priority"` + TableID int `ovsdb:"table_id"` + Tags map[string]string `ovsdb:"tags"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/mac_binding.go b/internal/server/network/openvswitch/schema/ovn-sb/mac_binding.go new file mode 100644 index 00000000000..f4201432c26 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/mac_binding.go @@ -0,0 +1,16 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const MACBindingTable = "MAC_Binding" + +// MACBinding defines an object in MAC_Binding table +type MACBinding struct { + UUID string `ovsdb:"_uuid"` + Datapath string `ovsdb:"datapath"` + IP string `ovsdb:"ip"` + LogicalPort string `ovsdb:"logical_port"` + MAC string `ovsdb:"mac"` + Timestamp int `ovsdb:"timestamp"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/meter.go b/internal/server/network/openvswitch/schema/ovn-sb/meter.go new file mode 100644 index 00000000000..b45b3cc0bb9 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/meter.go @@ -0,0 +1,23 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const MeterTable = "Meter" + +type ( + MeterUnit = string +) + +var ( + MeterUnitKbps MeterUnit = "kbps" + MeterUnitPktps MeterUnit = "pktps" +) + +// Meter defines an object in Meter table +type Meter struct { + UUID string `ovsdb:"_uuid"` + Bands []string `ovsdb:"bands"` + Name string `ovsdb:"name"` + Unit MeterUnit `ovsdb:"unit"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/meter_band.go b/internal/server/network/openvswitch/schema/ovn-sb/meter_band.go new file mode 100644 index 00000000000..16c0730a049 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/meter_band.go @@ -0,0 +1,22 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const MeterBandTable = "Meter_Band" + +type ( + MeterBandAction = string +) + +var ( + MeterBandActionDrop MeterBandAction = "drop" +) + +// MeterBand defines an object in Meter_Band table +type MeterBand struct { + UUID string `ovsdb:"_uuid"` + Action MeterBandAction `ovsdb:"action"` + BurstSize int `ovsdb:"burst_size"` + Rate int `ovsdb:"rate"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/mirror.go b/internal/server/network/openvswitch/schema/ovn-sb/mirror.go new file mode 100644 index 00000000000..8d3551ca1b0 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/mirror.go @@ -0,0 +1,29 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const MirrorTable = "Mirror" + +type ( + MirrorFilter = string + MirrorType = string +) + +var ( + MirrorFilterFromLport MirrorFilter = "from-lport" + MirrorFilterToLport MirrorFilter = "to-lport" + MirrorTypeGre MirrorType = "gre" + MirrorTypeErspan MirrorType = "erspan" +) + +// Mirror defines an object in Mirror table +type Mirror struct { + UUID string `ovsdb:"_uuid"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Filter MirrorFilter `ovsdb:"filter"` + Index int `ovsdb:"index"` + Name string `ovsdb:"name"` + Sink string `ovsdb:"sink"` + Type MirrorType `ovsdb:"type"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/model.go b/internal/server/network/openvswitch/schema/ovn-sb/model.go new file mode 100644 index 00000000000..083c964b566 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/model.go @@ -0,0 +1,1798 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +import ( + "encoding/json" + + "github.com/ovn-org/libovsdb/model" + "github.com/ovn-org/libovsdb/ovsdb" +) + +// FullDatabaseModel returns the DatabaseModel object to be used in libovsdb +func FullDatabaseModel() (model.ClientDBModel, error) { + return model.NewClientDBModel("OVN_Southbound", map[string]model.Model{ + "Address_Set": &AddressSet{}, + "BFD": &BFD{}, + "Chassis": &Chassis{}, + "Chassis_Private": &ChassisPrivate{}, + "Chassis_Template_Var": &ChassisTemplateVar{}, + "Connection": &Connection{}, + "Controller_Event": &ControllerEvent{}, + "DHCP_Options": &DHCPOptions{}, + "DHCPv6_Options": &DHCPv6Options{}, + "DNS": &DNS{}, + "Datapath_Binding": &DatapathBinding{}, + "Encap": &Encap{}, + "FDB": &FDB{}, + "Gateway_Chassis": &GatewayChassis{}, + "HA_Chassis": &HAChassis{}, + "HA_Chassis_Group": &HAChassisGroup{}, + "IGMP_Group": &IGMPGroup{}, + "IP_Multicast": &IPMulticast{}, + "Load_Balancer": &LoadBalancer{}, + "Logical_DP_Group": &LogicalDPGroup{}, + "Logical_Flow": &LogicalFlow{}, + "MAC_Binding": &MACBinding{}, + "Meter": &Meter{}, + "Meter_Band": &MeterBand{}, + "Mirror": &Mirror{}, + "Multicast_Group": &MulticastGroup{}, + "Port_Binding": &PortBinding{}, + "Port_Group": &PortGroup{}, + "RBAC_Permission": &RBACPermission{}, + "RBAC_Role": &RBACRole{}, + "SB_Global": &SBGlobal{}, + "SSL": &SSL{}, + "Service_Monitor": &ServiceMonitor{}, + "Static_MAC_Binding": &StaticMACBinding{}, + }) +} + +var schema = `{ + "name": "OVN_Southbound", + "version": "20.27.0", + "tables": { + "Address_Set": { + "columns": { + "addresses": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "name": { + "type": "string" + } + }, + "indexes": [ + [ + "name" + ] + ] + }, + "BFD": { + "columns": { + "detect_mult": { + "type": "integer" + }, + "disc": { + "type": "integer" + }, + "dst_ip": { + "type": "string" + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "logical_port": { + "type": "string" + }, + "min_rx": { + "type": "integer" + }, + "min_tx": { + "type": "integer" + }, + "options": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "src_port": { + "type": { + "key": { + "type": "integer", + "minInteger": 49152, + "maxInteger": 65535 + } + } + }, + "status": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "down", + "init", + "up", + "admin_down" + ] + ] + } + } + } + }, + "indexes": [ + [ + "logical_port", + "dst_ip", + "src_port", + "disc" + ] + ] + }, + "Chassis": { + "columns": { + "encaps": { + "type": { + "key": { + "type": "uuid", + "refTable": "Encap" + }, + "min": 1, + "max": "unlimited" + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "hostname": { + "type": "string" + }, + "name": { + "type": "string" + }, + "nb_cfg": { + "type": "integer" + }, + "other_config": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "transport_zones": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "vtep_logical_switches": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + } + }, + "indexes": [ + [ + "name" + ] + ] + }, + "Chassis_Private": { + "columns": { + "chassis": { + "type": { + "key": { + "type": "uuid", + "refTable": "Chassis", + "refType": "weak" + }, + "min": 0, + "max": 1 + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "name": { + "type": "string" + }, + "nb_cfg": { + "type": "integer" + }, + "nb_cfg_timestamp": { + "type": "integer" + } + }, + "indexes": [ + [ + "name" + ] + ] + }, + "Chassis_Template_Var": { + "columns": { + "chassis": { + "type": "string" + }, + "variables": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + } + }, + "indexes": [ + [ + "chassis" + ] + ] + }, + "Connection": { + "columns": { + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "inactivity_probe": { + "type": { + "key": { + "type": "integer" + }, + "min": 0, + "max": 1 + } + }, + "is_connected": { + "type": "boolean", + "ephemeral": true + }, + "max_backoff": { + "type": { + "key": { + "type": "integer", + "minInteger": 1000 + }, + "min": 0, + "max": 1 + } + }, + "other_config": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "read_only": { + "type": "boolean" + }, + "role": { + "type": "string" + }, + "status": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + }, + "ephemeral": true + }, + "target": { + "type": "string" + } + }, + "indexes": [ + [ + "target" + ] + ] + }, + "Controller_Event": { + "columns": { + "chassis": { + "type": { + "key": { + "type": "uuid", + "refTable": "Chassis", + "refType": "weak" + }, + "min": 0, + "max": 1 + } + }, + "event_info": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "event_type": { + "type": { + "key": { + "type": "string", + "enum": "empty_lb_backends" + } + } + }, + "seq_num": { + "type": "integer" + } + } + }, + "DHCP_Options": { + "columns": { + "code": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 254 + } + } + }, + "name": { + "type": "string" + }, + "type": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "bool", + "uint8", + "uint16", + "uint32", + "ipv4", + "static_routes", + "str", + "host_id", + "domains" + ] + ] + } + } + } + } + }, + "DHCPv6_Options": { + "columns": { + "code": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 254 + } + } + }, + "name": { + "type": "string" + }, + "type": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "ipv6", + "str", + "mac" + ] + ] + } + } + } + } + }, + "DNS": { + "columns": { + "datapaths": { + "type": { + "key": { + "type": "uuid", + "refTable": "Datapath_Binding" + }, + "min": 1, + "max": "unlimited" + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "records": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + } + } + }, + "Datapath_Binding": { + "columns": { + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "load_balancers": { + "type": { + "key": { + "type": "uuid" + }, + "min": 0, + "max": "unlimited" + } + }, + "tunnel_key": { + "type": { + "key": { + "type": "integer", + "minInteger": 1, + "maxInteger": 16777215 + } + } + } + }, + "indexes": [ + [ + "tunnel_key" + ] + ] + }, + "Encap": { + "columns": { + "chassis_name": { + "type": "string" + }, + "ip": { + "type": "string" + }, + "options": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "type": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "geneve", + "stt", + "vxlan" + ] + ] + } + } + } + }, + "indexes": [ + [ + "type", + "ip" + ] + ] + }, + "FDB": { + "columns": { + "dp_key": { + "type": { + "key": { + "type": "integer", + "minInteger": 1, + "maxInteger": 16777215 + } + } + }, + "mac": { + "type": "string" + }, + "port_key": { + "type": { + "key": { + "type": "integer", + "minInteger": 1, + "maxInteger": 16777215 + } + } + } + }, + "indexes": [ + [ + "mac", + "dp_key" + ] + ] + }, + "Gateway_Chassis": { + "columns": { + "chassis": { + "type": { + "key": { + "type": "uuid", + "refTable": "Chassis", + "refType": "weak" + }, + "min": 0, + "max": 1 + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "name": { + "type": "string" + }, + "options": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "priority": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 32767 + } + } + } + }, + "indexes": [ + [ + "name" + ] + ] + }, + "HA_Chassis": { + "columns": { + "chassis": { + "type": { + "key": { + "type": "uuid", + "refTable": "Chassis", + "refType": "weak" + }, + "min": 0, + "max": 1 + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "priority": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 32767 + } + } + } + } + }, + "HA_Chassis_Group": { + "columns": { + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "ha_chassis": { + "type": { + "key": { + "type": "uuid", + "refTable": "HA_Chassis", + "refType": "strong" + }, + "min": 0, + "max": "unlimited" + } + }, + "name": { + "type": "string" + }, + "ref_chassis": { + "type": { + "key": { + "type": "uuid", + "refTable": "Chassis", + "refType": "weak" + }, + "min": 0, + "max": "unlimited" + } + } + }, + "indexes": [ + [ + "name" + ] + ] + }, + "IGMP_Group": { + "columns": { + "address": { + "type": "string" + }, + "chassis": { + "type": { + "key": { + "type": "uuid", + "refTable": "Chassis", + "refType": "weak" + }, + "min": 0, + "max": 1 + } + }, + "datapath": { + "type": { + "key": { + "type": "uuid", + "refTable": "Datapath_Binding", + "refType": "weak" + }, + "min": 0, + "max": 1 + } + }, + "ports": { + "type": { + "key": { + "type": "uuid", + "refTable": "Port_Binding", + "refType": "weak" + }, + "min": 0, + "max": "unlimited" + } + } + }, + "indexes": [ + [ + "address", + "datapath", + "chassis" + ] + ] + }, + "IP_Multicast": { + "columns": { + "datapath": { + "type": { + "key": { + "type": "uuid", + "refTable": "Datapath_Binding", + "refType": "weak" + } + } + }, + "enabled": { + "type": { + "key": { + "type": "boolean" + }, + "min": 0, + "max": 1 + } + }, + "eth_src": { + "type": "string" + }, + "idle_timeout": { + "type": { + "key": { + "type": "integer" + }, + "min": 0, + "max": 1 + } + }, + "ip4_src": { + "type": "string" + }, + "ip6_src": { + "type": "string" + }, + "querier": { + "type": { + "key": { + "type": "boolean" + }, + "min": 0, + "max": 1 + } + }, + "query_interval": { + "type": { + "key": { + "type": "integer" + }, + "min": 0, + "max": 1 + } + }, + "query_max_resp": { + "type": { + "key": { + "type": "integer" + }, + "min": 0, + "max": 1 + } + }, + "seq_no": { + "type": "integer" + }, + "table_size": { + "type": { + "key": { + "type": "integer" + }, + "min": 0, + "max": 1 + } + } + }, + "indexes": [ + [ + "datapath" + ] + ] + }, + "Load_Balancer": { + "columns": { + "datapath_group": { + "type": { + "key": { + "type": "uuid", + "refTable": "Logical_DP_Group" + }, + "min": 0, + "max": 1 + } + }, + "datapaths": { + "type": { + "key": { + "type": "uuid", + "refTable": "Datapath_Binding" + }, + "min": 0, + "max": "unlimited" + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "name": { + "type": "string" + }, + "options": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "protocol": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "tcp", + "udp", + "sctp" + ] + ] + }, + "min": 0, + "max": 1 + } + }, + "vips": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + } + } + }, + "Logical_DP_Group": { + "columns": { + "datapaths": { + "type": { + "key": { + "type": "uuid", + "refTable": "Datapath_Binding", + "refType": "weak" + }, + "min": 0, + "max": "unlimited" + } + } + } + }, + "Logical_Flow": { + "columns": { + "actions": { + "type": "string" + }, + "controller_meter": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "logical_datapath": { + "type": { + "key": { + "type": "uuid", + "refTable": "Datapath_Binding" + }, + "min": 0, + "max": 1 + } + }, + "logical_dp_group": { + "type": { + "key": { + "type": "uuid", + "refTable": "Logical_DP_Group" + }, + "min": 0, + "max": 1 + } + }, + "match": { + "type": "string" + }, + "pipeline": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "ingress", + "egress" + ] + ] + } + } + }, + "priority": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 65535 + } + } + }, + "table_id": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 32 + } + } + }, + "tags": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + } + } + }, + "MAC_Binding": { + "columns": { + "datapath": { + "type": { + "key": { + "type": "uuid", + "refTable": "Datapath_Binding" + } + } + }, + "ip": { + "type": "string" + }, + "logical_port": { + "type": "string" + }, + "mac": { + "type": "string" + }, + "timestamp": { + "type": "integer" + } + }, + "indexes": [ + [ + "logical_port", + "ip" + ] + ] + }, + "Meter": { + "columns": { + "bands": { + "type": { + "key": { + "type": "uuid", + "refTable": "Meter_Band", + "refType": "strong" + }, + "min": 1, + "max": "unlimited" + } + }, + "name": { + "type": "string" + }, + "unit": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "kbps", + "pktps" + ] + ] + } + } + } + }, + "indexes": [ + [ + "name" + ] + ] + }, + "Meter_Band": { + "columns": { + "action": { + "type": { + "key": { + "type": "string", + "enum": "drop" + } + } + }, + "burst_size": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 4294967295 + } + } + }, + "rate": { + "type": { + "key": { + "type": "integer", + "minInteger": 1, + "maxInteger": 4294967295 + } + } + } + } + }, + "Mirror": { + "columns": { + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "filter": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "from-lport", + "to-lport" + ] + ] + } + } + }, + "index": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "sink": { + "type": "string" + }, + "type": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "gre", + "erspan" + ] + ] + } + } + } + }, + "indexes": [ + [ + "name" + ] + ] + }, + "Multicast_Group": { + "columns": { + "datapath": { + "type": { + "key": { + "type": "uuid", + "refTable": "Datapath_Binding" + } + } + }, + "name": { + "type": "string" + }, + "ports": { + "type": { + "key": { + "type": "uuid", + "refTable": "Port_Binding", + "refType": "weak" + }, + "min": 0, + "max": "unlimited" + } + }, + "tunnel_key": { + "type": { + "key": { + "type": "integer", + "minInteger": 32768, + "maxInteger": 65535 + } + } + } + }, + "indexes": [ + [ + "datapath", + "tunnel_key" + ], + [ + "datapath", + "name" + ] + ] + }, + "Port_Binding": { + "columns": { + "additional_chassis": { + "type": { + "key": { + "type": "uuid", + "refTable": "Chassis", + "refType": "weak" + }, + "min": 0, + "max": "unlimited" + } + }, + "additional_encap": { + "type": { + "key": { + "type": "uuid", + "refTable": "Encap", + "refType": "weak" + }, + "min": 0, + "max": "unlimited" + } + }, + "chassis": { + "type": { + "key": { + "type": "uuid", + "refTable": "Chassis", + "refType": "weak" + }, + "min": 0, + "max": 1 + } + }, + "datapath": { + "type": { + "key": { + "type": "uuid", + "refTable": "Datapath_Binding" + } + } + }, + "encap": { + "type": { + "key": { + "type": "uuid", + "refTable": "Encap", + "refType": "weak" + }, + "min": 0, + "max": 1 + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "gateway_chassis": { + "type": { + "key": { + "type": "uuid", + "refTable": "Gateway_Chassis", + "refType": "strong" + }, + "min": 0, + "max": "unlimited" + } + }, + "ha_chassis_group": { + "type": { + "key": { + "type": "uuid", + "refTable": "HA_Chassis_Group", + "refType": "strong" + }, + "min": 0, + "max": 1 + } + }, + "logical_port": { + "type": "string" + }, + "mac": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "mirror_rules": { + "type": { + "key": { + "type": "uuid", + "refTable": "Mirror", + "refType": "weak" + }, + "min": 0, + "max": "unlimited" + } + }, + "nat_addresses": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "options": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "parent_port": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "port_security": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "requested_additional_chassis": { + "type": { + "key": { + "type": "uuid", + "refTable": "Chassis", + "refType": "weak" + }, + "min": 0, + "max": "unlimited" + } + }, + "requested_chassis": { + "type": { + "key": { + "type": "uuid", + "refTable": "Chassis", + "refType": "weak" + }, + "min": 0, + "max": 1 + } + }, + "tag": { + "type": { + "key": { + "type": "integer", + "minInteger": 1, + "maxInteger": 4095 + }, + "min": 0, + "max": 1 + } + }, + "tunnel_key": { + "type": { + "key": { + "type": "integer", + "minInteger": 1, + "maxInteger": 32767 + } + } + }, + "type": { + "type": "string" + }, + "up": { + "type": { + "key": { + "type": "boolean" + }, + "min": 0, + "max": 1 + } + }, + "virtual_parent": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + } + }, + "indexes": [ + [ + "datapath", + "tunnel_key" + ], + [ + "logical_port" + ] + ] + }, + "Port_Group": { + "columns": { + "name": { + "type": "string" + }, + "ports": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + } + }, + "indexes": [ + [ + "name" + ] + ] + }, + "RBAC_Permission": { + "columns": { + "authorization": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "insert_delete": { + "type": "boolean" + }, + "table": { + "type": "string" + }, + "update": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + } + } + }, + "RBAC_Role": { + "columns": { + "name": { + "type": "string" + }, + "permissions": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "uuid", + "refTable": "RBAC_Permission", + "refType": "weak" + }, + "min": 0, + "max": "unlimited" + } + } + } + }, + "SB_Global": { + "columns": { + "connections": { + "type": { + "key": { + "type": "uuid", + "refTable": "Connection" + }, + "min": 0, + "max": "unlimited" + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "ipsec": { + "type": "boolean" + }, + "nb_cfg": { + "type": "integer" + }, + "options": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "ssl": { + "type": { + "key": { + "type": "uuid", + "refTable": "SSL" + }, + "min": 0, + "max": 1 + } + } + } + }, + "SSL": { + "columns": { + "bootstrap_ca_cert": { + "type": "boolean" + }, + "ca_cert": { + "type": "string" + }, + "certificate": { + "type": "string" + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "private_key": { + "type": "string" + }, + "ssl_ciphers": { + "type": "string" + }, + "ssl_protocols": { + "type": "string" + } + } + }, + "Service_Monitor": { + "columns": { + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "ip": { + "type": "string" + }, + "logical_port": { + "type": "string" + }, + "options": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "port": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 65535 + } + } + }, + "protocol": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "tcp", + "udp" + ] + ] + }, + "min": 0, + "max": 1 + } + }, + "src_ip": { + "type": "string" + }, + "src_mac": { + "type": "string" + }, + "status": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "online", + "offline", + "error" + ] + ] + }, + "min": 0, + "max": 1 + } + } + }, + "indexes": [ + [ + "logical_port", + "ip", + "port", + "protocol" + ] + ] + }, + "Static_MAC_Binding": { + "columns": { + "datapath": { + "type": { + "key": { + "type": "uuid", + "refTable": "Datapath_Binding" + } + } + }, + "ip": { + "type": "string" + }, + "logical_port": { + "type": "string" + }, + "mac": { + "type": "string" + }, + "override_dynamic_mac": { + "type": "boolean" + } + }, + "indexes": [ + [ + "logical_port", + "ip" + ] + ] + } + } +}` + +func Schema() ovsdb.DatabaseSchema { + var s ovsdb.DatabaseSchema + err := json.Unmarshal([]byte(schema), &s) + if err != nil { + panic(err) + } + return s +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/multicast_group.go b/internal/server/network/openvswitch/schema/ovn-sb/multicast_group.go new file mode 100644 index 00000000000..02b0ead2789 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/multicast_group.go @@ -0,0 +1,15 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const MulticastGroupTable = "Multicast_Group" + +// MulticastGroup defines an object in Multicast_Group table +type MulticastGroup struct { + UUID string `ovsdb:"_uuid"` + Datapath string `ovsdb:"datapath"` + Name string `ovsdb:"name"` + Ports []string `ovsdb:"ports"` + TunnelKey int `ovsdb:"tunnel_key"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/port_binding.go b/internal/server/network/openvswitch/schema/ovn-sb/port_binding.go new file mode 100644 index 00000000000..fe9d0bf508b --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/port_binding.go @@ -0,0 +1,33 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const PortBindingTable = "Port_Binding" + +// PortBinding defines an object in Port_Binding table +type PortBinding struct { + UUID string `ovsdb:"_uuid"` + AdditionalChassis []string `ovsdb:"additional_chassis"` + AdditionalEncap []string `ovsdb:"additional_encap"` + Chassis *string `ovsdb:"chassis"` + Datapath string `ovsdb:"datapath"` + Encap *string `ovsdb:"encap"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + GatewayChassis []string `ovsdb:"gateway_chassis"` + HaChassisGroup *string `ovsdb:"ha_chassis_group"` + LogicalPort string `ovsdb:"logical_port"` + MAC []string `ovsdb:"mac"` + MirrorRules []string `ovsdb:"mirror_rules"` + NatAddresses []string `ovsdb:"nat_addresses"` + Options map[string]string `ovsdb:"options"` + ParentPort *string `ovsdb:"parent_port"` + PortSecurity []string `ovsdb:"port_security"` + RequestedAdditionalChassis []string `ovsdb:"requested_additional_chassis"` + RequestedChassis *string `ovsdb:"requested_chassis"` + Tag *int `ovsdb:"tag"` + TunnelKey int `ovsdb:"tunnel_key"` + Type string `ovsdb:"type"` + Up *bool `ovsdb:"up"` + VirtualParent *string `ovsdb:"virtual_parent"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/port_group.go b/internal/server/network/openvswitch/schema/ovn-sb/port_group.go new file mode 100644 index 00000000000..d0f652ffab2 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/port_group.go @@ -0,0 +1,13 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const PortGroupTable = "Port_Group" + +// PortGroup defines an object in Port_Group table +type PortGroup struct { + UUID string `ovsdb:"_uuid"` + Name string `ovsdb:"name"` + Ports []string `ovsdb:"ports"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/rbac_permission.go b/internal/server/network/openvswitch/schema/ovn-sb/rbac_permission.go new file mode 100644 index 00000000000..99a584cbaeb --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/rbac_permission.go @@ -0,0 +1,15 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const RBACPermissionTable = "RBAC_Permission" + +// RBACPermission defines an object in RBAC_Permission table +type RBACPermission struct { + UUID string `ovsdb:"_uuid"` + Authorization []string `ovsdb:"authorization"` + InsertDelete bool `ovsdb:"insert_delete"` + Table string `ovsdb:"table"` + Update []string `ovsdb:"update"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/rbac_role.go b/internal/server/network/openvswitch/schema/ovn-sb/rbac_role.go new file mode 100644 index 00000000000..af7ecf59538 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/rbac_role.go @@ -0,0 +1,13 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const RBACRoleTable = "RBAC_Role" + +// RBACRole defines an object in RBAC_Role table +type RBACRole struct { + UUID string `ovsdb:"_uuid"` + Name string `ovsdb:"name"` + Permissions map[string]string `ovsdb:"permissions"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/sb_global.go b/internal/server/network/openvswitch/schema/ovn-sb/sb_global.go new file mode 100644 index 00000000000..3d65fd3b324 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/sb_global.go @@ -0,0 +1,17 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const SBGlobalTable = "SB_Global" + +// SBGlobal defines an object in SB_Global table +type SBGlobal struct { + UUID string `ovsdb:"_uuid"` + Connections []string `ovsdb:"connections"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Ipsec bool `ovsdb:"ipsec"` + NbCfg int `ovsdb:"nb_cfg"` + Options map[string]string `ovsdb:"options"` + SSL *string `ovsdb:"ssl"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/service_monitor.go b/internal/server/network/openvswitch/schema/ovn-sb/service_monitor.go new file mode 100644 index 00000000000..c40c36ba810 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/service_monitor.go @@ -0,0 +1,33 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const ServiceMonitorTable = "Service_Monitor" + +type ( + ServiceMonitorProtocol = string + ServiceMonitorStatus = string +) + +var ( + ServiceMonitorProtocolTCP ServiceMonitorProtocol = "tcp" + ServiceMonitorProtocolUDP ServiceMonitorProtocol = "udp" + ServiceMonitorStatusOnline ServiceMonitorStatus = "online" + ServiceMonitorStatusOffline ServiceMonitorStatus = "offline" + ServiceMonitorStatusError ServiceMonitorStatus = "error" +) + +// ServiceMonitor defines an object in Service_Monitor table +type ServiceMonitor struct { + UUID string `ovsdb:"_uuid"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + IP string `ovsdb:"ip"` + LogicalPort string `ovsdb:"logical_port"` + Options map[string]string `ovsdb:"options"` + Port int `ovsdb:"port"` + Protocol *ServiceMonitorProtocol `ovsdb:"protocol"` + SrcIP string `ovsdb:"src_ip"` + SrcMAC string `ovsdb:"src_mac"` + Status *ServiceMonitorStatus `ovsdb:"status"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/ssl.go b/internal/server/network/openvswitch/schema/ovn-sb/ssl.go new file mode 100644 index 00000000000..2cfd4305eff --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/ssl.go @@ -0,0 +1,18 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const SSLTable = "SSL" + +// SSL defines an object in SSL table +type SSL struct { + UUID string `ovsdb:"_uuid"` + BootstrapCaCert bool `ovsdb:"bootstrap_ca_cert"` + CaCert string `ovsdb:"ca_cert"` + Certificate string `ovsdb:"certificate"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + PrivateKey string `ovsdb:"private_key"` + SSLCiphers string `ovsdb:"ssl_ciphers"` + SSLProtocols string `ovsdb:"ssl_protocols"` +} diff --git a/internal/server/network/openvswitch/schema/ovn-sb/static_mac_binding.go b/internal/server/network/openvswitch/schema/ovn-sb/static_mac_binding.go new file mode 100644 index 00000000000..54b2e6ff33d --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovn-sb/static_mac_binding.go @@ -0,0 +1,16 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const StaticMACBindingTable = "Static_MAC_Binding" + +// StaticMACBinding defines an object in Static_MAC_Binding table +type StaticMACBinding struct { + UUID string `ovsdb:"_uuid"` + Datapath string `ovsdb:"datapath"` + IP string `ovsdb:"ip"` + LogicalPort string `ovsdb:"logical_port"` + MAC string `ovsdb:"mac"` + OverrideDynamicMAC bool `ovsdb:"override_dynamic_mac"` +} diff --git a/internal/server/network/openvswitch/schema/ovs/autoattach.go b/internal/server/network/openvswitch/schema/ovs/autoattach.go new file mode 100644 index 00000000000..80bb963b4fb --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovs/autoattach.go @@ -0,0 +1,14 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const AutoAttachTable = "AutoAttach" + +// AutoAttach defines an object in AutoAttach table +type AutoAttach struct { + UUID string `ovsdb:"_uuid"` + Mappings map[int]int `ovsdb:"mappings"` + SystemDescription string `ovsdb:"system_description"` + SystemName string `ovsdb:"system_name"` +} diff --git a/internal/server/network/openvswitch/schema/ovs/bridge.go b/internal/server/network/openvswitch/schema/ovs/bridge.go new file mode 100644 index 00000000000..c7648d07277 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovs/bridge.go @@ -0,0 +1,49 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const BridgeTable = "Bridge" + +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 +type Bridge struct { + UUID string `ovsdb:"_uuid"` + AutoAttach *string `ovsdb:"auto_attach"` + Controller []string `ovsdb:"controller"` + DatapathID *string `ovsdb:"datapath_id"` + DatapathType string `ovsdb:"datapath_type"` + DatapathVersion string `ovsdb:"datapath_version"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + FailMode *BridgeFailMode `ovsdb:"fail_mode"` + FloodVLANs []int `ovsdb:"flood_vlans"` + FlowTables map[int]string `ovsdb:"flow_tables"` + IPFIX *string `ovsdb:"ipfix"` + McastSnoopingEnable bool `ovsdb:"mcast_snooping_enable"` + Mirrors []string `ovsdb:"mirrors"` + Name string `ovsdb:"name"` + Netflow *string `ovsdb:"netflow"` + OtherConfig map[string]string `ovsdb:"other_config"` + Ports []string `ovsdb:"ports"` + Protocols []BridgeProtocols `ovsdb:"protocols"` + RSTPEnable bool `ovsdb:"rstp_enable"` + RSTPStatus map[string]string `ovsdb:"rstp_status"` + Sflow *string `ovsdb:"sflow"` + Status map[string]string `ovsdb:"status"` + STPEnable bool `ovsdb:"stp_enable"` +} diff --git a/internal/server/network/openvswitch/schema/ovs/controller.go b/internal/server/network/openvswitch/schema/ovs/controller.go new file mode 100644 index 00000000000..c9b75a17e08 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovs/controller.go @@ -0,0 +1,44 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const ControllerTable = "Controller" + +type ( + ControllerConnectionMode = string + ControllerRole = string + ControllerType = string +) + +var ( + ControllerConnectionModeInBand ControllerConnectionMode = "in-band" + ControllerConnectionModeOutOfBand ControllerConnectionMode = "out-of-band" + ControllerRoleOther ControllerRole = "other" + ControllerRoleMaster ControllerRole = "master" + ControllerRoleSlave ControllerRole = "slave" + ControllerTypePrimary ControllerType = "primary" + ControllerTypeService ControllerType = "service" +) + +// Controller defines an object in Controller table +type Controller struct { + UUID string `ovsdb:"_uuid"` + ConnectionMode *ControllerConnectionMode `ovsdb:"connection_mode"` + ControllerBurstLimit *int `ovsdb:"controller_burst_limit"` + ControllerQueueSize *int `ovsdb:"controller_queue_size"` + ControllerRateLimit *int `ovsdb:"controller_rate_limit"` + EnableAsyncMessages *bool `ovsdb:"enable_async_messages"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + InactivityProbe *int `ovsdb:"inactivity_probe"` + IsConnected bool `ovsdb:"is_connected"` + LocalGateway *string `ovsdb:"local_gateway"` + LocalIP *string `ovsdb:"local_ip"` + LocalNetmask *string `ovsdb:"local_netmask"` + MaxBackoff *int `ovsdb:"max_backoff"` + OtherConfig map[string]string `ovsdb:"other_config"` + Role *ControllerRole `ovsdb:"role"` + Status map[string]string `ovsdb:"status"` + Target string `ovsdb:"target"` + Type *ControllerType `ovsdb:"type"` +} diff --git a/internal/server/network/openvswitch/schema/ovs/ct_timeout_policy.go b/internal/server/network/openvswitch/schema/ovs/ct_timeout_policy.go new file mode 100644 index 00000000000..7b3e46f0353 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovs/ct_timeout_policy.go @@ -0,0 +1,36 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const CTTimeoutPolicyTable = "CT_Timeout_Policy" + +type ( + CTTimeoutPolicyTimeouts = string +) + +var ( + CTTimeoutPolicyTimeoutsTCPSynSent CTTimeoutPolicyTimeouts = "tcp_syn_sent" + CTTimeoutPolicyTimeoutsTCPSynRecv CTTimeoutPolicyTimeouts = "tcp_syn_recv" + CTTimeoutPolicyTimeoutsTCPEstablished CTTimeoutPolicyTimeouts = "tcp_established" + CTTimeoutPolicyTimeoutsTCPFinWait CTTimeoutPolicyTimeouts = "tcp_fin_wait" + CTTimeoutPolicyTimeoutsTCPCloseWait CTTimeoutPolicyTimeouts = "tcp_close_wait" + CTTimeoutPolicyTimeoutsTCPLastAck CTTimeoutPolicyTimeouts = "tcp_last_ack" + CTTimeoutPolicyTimeoutsTCPTimeWait CTTimeoutPolicyTimeouts = "tcp_time_wait" + CTTimeoutPolicyTimeoutsTCPClose CTTimeoutPolicyTimeouts = "tcp_close" + CTTimeoutPolicyTimeoutsTCPSynSent2 CTTimeoutPolicyTimeouts = "tcp_syn_sent2" + CTTimeoutPolicyTimeoutsTCPRetransmit CTTimeoutPolicyTimeouts = "tcp_retransmit" + CTTimeoutPolicyTimeoutsTCPUnack CTTimeoutPolicyTimeouts = "tcp_unack" + CTTimeoutPolicyTimeoutsUDPFirst CTTimeoutPolicyTimeouts = "udp_first" + CTTimeoutPolicyTimeoutsUDPSingle CTTimeoutPolicyTimeouts = "udp_single" + CTTimeoutPolicyTimeoutsUDPMultiple CTTimeoutPolicyTimeouts = "udp_multiple" + CTTimeoutPolicyTimeoutsICMPFirst CTTimeoutPolicyTimeouts = "icmp_first" + CTTimeoutPolicyTimeoutsICMPReply CTTimeoutPolicyTimeouts = "icmp_reply" +) + +// CTTimeoutPolicy defines an object in CT_Timeout_Policy table +type CTTimeoutPolicy struct { + UUID string `ovsdb:"_uuid"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Timeouts map[string]int `ovsdb:"timeouts"` +} diff --git a/internal/server/network/openvswitch/schema/ovs/ct_zone.go b/internal/server/network/openvswitch/schema/ovs/ct_zone.go new file mode 100644 index 00000000000..f1f1d19ab6f --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovs/ct_zone.go @@ -0,0 +1,13 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const CTZoneTable = "CT_Zone" + +// CTZone defines an object in CT_Zone table +type CTZone struct { + UUID string `ovsdb:"_uuid"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + TimeoutPolicy *string `ovsdb:"timeout_policy"` +} diff --git a/internal/server/network/openvswitch/schema/ovs/datapath.go b/internal/server/network/openvswitch/schema/ovs/datapath.go new file mode 100644 index 00000000000..ca46a6c0fb6 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovs/datapath.go @@ -0,0 +1,15 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const DatapathTable = "Datapath" + +// Datapath defines an object in Datapath table +type Datapath struct { + UUID string `ovsdb:"_uuid"` + Capabilities map[string]string `ovsdb:"capabilities"` + CTZones map[int]string `ovsdb:"ct_zones"` + DatapathVersion string `ovsdb:"datapath_version"` + ExternalIDs map[string]string `ovsdb:"external_ids"` +} diff --git a/internal/server/network/openvswitch/schema/ovs/flow_sample_collector_set.go b/internal/server/network/openvswitch/schema/ovs/flow_sample_collector_set.go new file mode 100644 index 00000000000..ae6c338a8ee --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovs/flow_sample_collector_set.go @@ -0,0 +1,15 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const FlowSampleCollectorSetTable = "Flow_Sample_Collector_Set" + +// FlowSampleCollectorSet defines an object in Flow_Sample_Collector_Set table +type FlowSampleCollectorSet struct { + UUID string `ovsdb:"_uuid"` + Bridge string `ovsdb:"bridge"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + ID int `ovsdb:"id"` + IPFIX *string `ovsdb:"ipfix"` +} diff --git a/internal/server/network/openvswitch/schema/ovs/flow_table.go b/internal/server/network/openvswitch/schema/ovs/flow_table.go new file mode 100644 index 00000000000..84f8599c589 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovs/flow_table.go @@ -0,0 +1,26 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const FlowTableTable = "Flow_Table" + +type ( + FlowTableOverflowPolicy = string +) + +var ( + FlowTableOverflowPolicyRefuse FlowTableOverflowPolicy = "refuse" + FlowTableOverflowPolicyEvict FlowTableOverflowPolicy = "evict" +) + +// FlowTable defines an object in Flow_Table table +type FlowTable struct { + UUID string `ovsdb:"_uuid"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + FlowLimit *int `ovsdb:"flow_limit"` + Groups []string `ovsdb:"groups"` + Name *string `ovsdb:"name"` + OverflowPolicy *FlowTableOverflowPolicy `ovsdb:"overflow_policy"` + Prefixes []string `ovsdb:"prefixes"` +} diff --git a/internal/server/network/openvswitch/schema/ovs/interface.go b/internal/server/network/openvswitch/schema/ovs/interface.go new file mode 100644 index 00000000000..78f6082fa9b --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovs/interface.go @@ -0,0 +1,62 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const InterfaceTable = "Interface" + +type ( + InterfaceAdminState = string + InterfaceCFMRemoteOpstate = string + InterfaceDuplex = string + InterfaceLinkState = string +) + +var ( + InterfaceAdminStateUp InterfaceAdminState = "up" + InterfaceAdminStateDown InterfaceAdminState = "down" + InterfaceCFMRemoteOpstateUp InterfaceCFMRemoteOpstate = "up" + InterfaceCFMRemoteOpstateDown InterfaceCFMRemoteOpstate = "down" + InterfaceDuplexHalf InterfaceDuplex = "half" + InterfaceDuplexFull InterfaceDuplex = "full" + InterfaceLinkStateUp InterfaceLinkState = "up" + InterfaceLinkStateDown InterfaceLinkState = "down" +) + +// Interface defines an object in Interface table +type Interface struct { + UUID string `ovsdb:"_uuid"` + AdminState *InterfaceAdminState `ovsdb:"admin_state"` + BFD map[string]string `ovsdb:"bfd"` + BFDStatus map[string]string `ovsdb:"bfd_status"` + CFMFault *bool `ovsdb:"cfm_fault"` + CFMFaultStatus []string `ovsdb:"cfm_fault_status"` + CFMFlapCount *int `ovsdb:"cfm_flap_count"` + CFMHealth *int `ovsdb:"cfm_health"` + CFMMpid *int `ovsdb:"cfm_mpid"` + CFMRemoteMpids []int `ovsdb:"cfm_remote_mpids"` + CFMRemoteOpstate *InterfaceCFMRemoteOpstate `ovsdb:"cfm_remote_opstate"` + Duplex *InterfaceDuplex `ovsdb:"duplex"` + Error *string `ovsdb:"error"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Ifindex *int `ovsdb:"ifindex"` + IngressPolicingBurst int `ovsdb:"ingress_policing_burst"` + IngressPolicingRate int `ovsdb:"ingress_policing_rate"` + LACPCurrent *bool `ovsdb:"lacp_current"` + LinkResets *int `ovsdb:"link_resets"` + LinkSpeed *int `ovsdb:"link_speed"` + LinkState *InterfaceLinkState `ovsdb:"link_state"` + LLDP map[string]string `ovsdb:"lldp"` + MAC *string `ovsdb:"mac"` + MACInUse *string `ovsdb:"mac_in_use"` + MTU *int `ovsdb:"mtu"` + MTURequest *int `ovsdb:"mtu_request"` + Name string `ovsdb:"name"` + Ofport *int `ovsdb:"ofport"` + OfportRequest *int `ovsdb:"ofport_request"` + Options map[string]string `ovsdb:"options"` + OtherConfig map[string]string `ovsdb:"other_config"` + Statistics map[string]int `ovsdb:"statistics"` + Status map[string]string `ovsdb:"status"` + Type string `ovsdb:"type"` +} diff --git a/internal/server/network/openvswitch/schema/ovs/ipfix.go b/internal/server/network/openvswitch/schema/ovs/ipfix.go new file mode 100644 index 00000000000..e272d7ec35b --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovs/ipfix.go @@ -0,0 +1,19 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const IPFIXTable = "IPFIX" + +// IPFIX defines an object in IPFIX table +type IPFIX struct { + UUID string `ovsdb:"_uuid"` + CacheActiveTimeout *int `ovsdb:"cache_active_timeout"` + CacheMaxFlows *int `ovsdb:"cache_max_flows"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + ObsDomainID *int `ovsdb:"obs_domain_id"` + ObsPointID *int `ovsdb:"obs_point_id"` + OtherConfig map[string]string `ovsdb:"other_config"` + Sampling *int `ovsdb:"sampling"` + Targets []string `ovsdb:"targets"` +} diff --git a/internal/server/network/openvswitch/schema/ovs/manager.go b/internal/server/network/openvswitch/schema/ovs/manager.go new file mode 100644 index 00000000000..901c2207b71 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovs/manager.go @@ -0,0 +1,28 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const ManagerTable = "Manager" + +type ( + ManagerConnectionMode = string +) + +var ( + ManagerConnectionModeInBand ManagerConnectionMode = "in-band" + ManagerConnectionModeOutOfBand ManagerConnectionMode = "out-of-band" +) + +// Manager defines an object in Manager table +type Manager struct { + UUID string `ovsdb:"_uuid"` + ConnectionMode *ManagerConnectionMode `ovsdb:"connection_mode"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + InactivityProbe *int `ovsdb:"inactivity_probe"` + IsConnected bool `ovsdb:"is_connected"` + MaxBackoff *int `ovsdb:"max_backoff"` + OtherConfig map[string]string `ovsdb:"other_config"` + Status map[string]string `ovsdb:"status"` + Target string `ovsdb:"target"` +} diff --git a/internal/server/network/openvswitch/schema/ovs/mirror.go b/internal/server/network/openvswitch/schema/ovs/mirror.go new file mode 100644 index 00000000000..059cd4e3628 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovs/mirror.go @@ -0,0 +1,21 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const MirrorTable = "Mirror" + +// Mirror defines an object in Mirror table +type Mirror struct { + UUID string `ovsdb:"_uuid"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Name string `ovsdb:"name"` + OutputPort *string `ovsdb:"output_port"` + OutputVLAN *int `ovsdb:"output_vlan"` + SelectAll bool `ovsdb:"select_all"` + SelectDstPort []string `ovsdb:"select_dst_port"` + SelectSrcPort []string `ovsdb:"select_src_port"` + SelectVLAN []int `ovsdb:"select_vlan"` + Snaplen *int `ovsdb:"snaplen"` + Statistics map[string]int `ovsdb:"statistics"` +} diff --git a/internal/server/network/openvswitch/schema/ovs/model.go b/internal/server/network/openvswitch/schema/ovs/model.go new file mode 100644 index 00000000000..cf42185edc7 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovs/model.go @@ -0,0 +1,1992 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +import ( + "encoding/json" + + "github.com/ovn-org/libovsdb/model" + "github.com/ovn-org/libovsdb/ovsdb" +) + +// FullDatabaseModel returns the DatabaseModel object to be used in libovsdb +func FullDatabaseModel() (model.ClientDBModel, error) { + return model.NewClientDBModel("Open_vSwitch", map[string]model.Model{ + "AutoAttach": &AutoAttach{}, + "Bridge": &Bridge{}, + "CT_Timeout_Policy": &CTTimeoutPolicy{}, + "CT_Zone": &CTZone{}, + "Controller": &Controller{}, + "Datapath": &Datapath{}, + "Flow_Sample_Collector_Set": &FlowSampleCollectorSet{}, + "Flow_Table": &FlowTable{}, + "IPFIX": &IPFIX{}, + "Interface": &Interface{}, + "Manager": &Manager{}, + "Mirror": &Mirror{}, + "NetFlow": &NetFlow{}, + "Open_vSwitch": &OpenvSwitch{}, + "Port": &Port{}, + "QoS": &QoS{}, + "Queue": &Queue{}, + "SSL": &SSL{}, + "sFlow": &SFlow{}, + }) +} + +var schema = `{ + "name": "Open_vSwitch", + "version": "8.2.0", + "tables": { + "AutoAttach": { + "columns": { + "mappings": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 16777215 + }, + "value": { + "type": "integer", + "minInteger": 0, + "maxInteger": 4095 + }, + "min": 0, + "max": "unlimited" + } + }, + "system_description": { + "type": "string" + }, + "system_name": { + "type": "string" + } + } + }, + "Bridge": { + "columns": { + "auto_attach": { + "type": { + "key": { + "type": "uuid", + "refTable": "AutoAttach" + }, + "min": 0, + "max": 1 + } + }, + "controller": { + "type": { + "key": { + "type": "uuid", + "refTable": "Controller" + }, + "min": 0, + "max": "unlimited" + } + }, + "datapath_id": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + }, + "ephemeral": true + }, + "datapath_type": { + "type": "string" + }, + "datapath_version": { + "type": "string" + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "fail_mode": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "standalone", + "secure" + ] + ] + }, + "min": 0, + "max": 1 + } + }, + "flood_vlans": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 4095 + }, + "min": 0, + "max": 4096 + } + }, + "flow_tables": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 254 + }, + "value": { + "type": "uuid", + "refTable": "Flow_Table" + }, + "min": 0, + "max": "unlimited" + } + }, + "ipfix": { + "type": { + "key": { + "type": "uuid", + "refTable": "IPFIX" + }, + "min": 0, + "max": 1 + } + }, + "mcast_snooping_enable": { + "type": "boolean" + }, + "mirrors": { + "type": { + "key": { + "type": "uuid", + "refTable": "Mirror" + }, + "min": 0, + "max": "unlimited" + } + }, + "name": { + "type": "string", + "mutable": false + }, + "netflow": { + "type": { + "key": { + "type": "uuid", + "refTable": "NetFlow" + }, + "min": 0, + "max": 1 + } + }, + "other_config": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "ports": { + "type": { + "key": { + "type": "uuid", + "refTable": "Port" + }, + "min": 0, + "max": "unlimited" + } + }, + "protocols": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "OpenFlow10", + "OpenFlow11", + "OpenFlow12", + "OpenFlow13", + "OpenFlow14", + "OpenFlow15" + ] + ] + }, + "min": 0, + "max": "unlimited" + } + }, + "rstp_enable": { + "type": "boolean" + }, + "rstp_status": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + }, + "ephemeral": true + }, + "sflow": { + "type": { + "key": { + "type": "uuid", + "refTable": "sFlow" + }, + "min": 0, + "max": 1 + } + }, + "status": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + }, + "ephemeral": true + }, + "stp_enable": { + "type": "boolean" + } + }, + "indexes": [ + [ + "name" + ] + ] + }, + "CT_Timeout_Policy": { + "columns": { + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "timeouts": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "tcp_syn_sent", + "tcp_syn_recv", + "tcp_established", + "tcp_fin_wait", + "tcp_close_wait", + "tcp_last_ack", + "tcp_time_wait", + "tcp_close", + "tcp_syn_sent2", + "tcp_retransmit", + "tcp_unack", + "udp_first", + "udp_single", + "udp_multiple", + "icmp_first", + "icmp_reply" + ] + ] + }, + "value": { + "type": "integer", + "minInteger": 0, + "maxInteger": 4294967295 + }, + "min": 0, + "max": "unlimited" + } + } + } + }, + "CT_Zone": { + "columns": { + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "timeout_policy": { + "type": { + "key": { + "type": "uuid", + "refTable": "CT_Timeout_Policy" + }, + "min": 0, + "max": 1 + } + } + } + }, + "Controller": { + "columns": { + "connection_mode": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "in-band", + "out-of-band" + ] + ] + }, + "min": 0, + "max": 1 + } + }, + "controller_burst_limit": { + "type": { + "key": { + "type": "integer", + "minInteger": 25 + }, + "min": 0, + "max": 1 + } + }, + "controller_queue_size": { + "type": { + "key": { + "type": "integer", + "minInteger": 1, + "maxInteger": 512 + }, + "min": 0, + "max": 1 + } + }, + "controller_rate_limit": { + "type": { + "key": { + "type": "integer", + "minInteger": 100 + }, + "min": 0, + "max": 1 + } + }, + "enable_async_messages": { + "type": { + "key": { + "type": "boolean" + }, + "min": 0, + "max": 1 + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "inactivity_probe": { + "type": { + "key": { + "type": "integer" + }, + "min": 0, + "max": 1 + } + }, + "is_connected": { + "type": "boolean", + "ephemeral": true + }, + "local_gateway": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "local_ip": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "local_netmask": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "max_backoff": { + "type": { + "key": { + "type": "integer", + "minInteger": 1000 + }, + "min": 0, + "max": 1 + } + }, + "other_config": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "role": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "other", + "master", + "slave" + ] + ] + }, + "min": 0, + "max": 1 + }, + "ephemeral": true + }, + "status": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + }, + "ephemeral": true + }, + "target": { + "type": "string" + }, + "type": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "primary", + "service" + ] + ] + }, + "min": 0, + "max": 1 + } + } + } + }, + "Datapath": { + "columns": { + "capabilities": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "ct_zones": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 65535 + }, + "value": { + "type": "uuid", + "refTable": "CT_Zone" + }, + "min": 0, + "max": "unlimited" + } + }, + "datapath_version": { + "type": "string" + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + } + } + }, + "Flow_Sample_Collector_Set": { + "columns": { + "bridge": { + "type": { + "key": { + "type": "uuid", + "refTable": "Bridge" + }, + "min": 1, + "max": 1 + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "id": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 4294967295 + }, + "min": 1, + "max": 1 + } + }, + "ipfix": { + "type": { + "key": { + "type": "uuid", + "refTable": "IPFIX" + }, + "min": 0, + "max": 1 + } + } + }, + "indexes": [ + [ + "id", + "bridge" + ] + ] + }, + "Flow_Table": { + "columns": { + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "flow_limit": { + "type": { + "key": { + "type": "integer", + "minInteger": 0 + }, + "min": 0, + "max": 1 + } + }, + "groups": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "name": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "overflow_policy": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "refuse", + "evict" + ] + ] + }, + "min": 0, + "max": 1 + } + }, + "prefixes": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 3 + } + } + } + }, + "IPFIX": { + "columns": { + "cache_active_timeout": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 4200 + }, + "min": 0, + "max": 1 + } + }, + "cache_max_flows": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 4294967295 + }, + "min": 0, + "max": 1 + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "obs_domain_id": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 4294967295 + }, + "min": 0, + "max": 1 + } + }, + "obs_point_id": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 4294967295 + }, + "min": 0, + "max": 1 + } + }, + "other_config": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "sampling": { + "type": { + "key": { + "type": "integer", + "minInteger": 1, + "maxInteger": 4294967295 + }, + "min": 0, + "max": 1 + } + }, + "targets": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + } + } + }, + "Interface": { + "columns": { + "admin_state": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "up", + "down" + ] + ] + }, + "min": 0, + "max": 1 + }, + "ephemeral": true + }, + "bfd": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "bfd_status": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "cfm_fault": { + "type": { + "key": { + "type": "boolean" + }, + "min": 0, + "max": 1 + }, + "ephemeral": true + }, + "cfm_fault_status": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + }, + "ephemeral": true + }, + "cfm_flap_count": { + "type": { + "key": { + "type": "integer" + }, + "min": 0, + "max": 1 + } + }, + "cfm_health": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 100 + }, + "min": 0, + "max": 1 + }, + "ephemeral": true + }, + "cfm_mpid": { + "type": { + "key": { + "type": "integer" + }, + "min": 0, + "max": 1 + } + }, + "cfm_remote_mpids": { + "type": { + "key": { + "type": "integer" + }, + "min": 0, + "max": "unlimited" + }, + "ephemeral": true + }, + "cfm_remote_opstate": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "up", + "down" + ] + ] + }, + "min": 0, + "max": 1 + }, + "ephemeral": true + }, + "duplex": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "half", + "full" + ] + ] + }, + "min": 0, + "max": 1 + }, + "ephemeral": true + }, + "error": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "ifindex": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 4294967295 + }, + "min": 0, + "max": 1 + }, + "ephemeral": true + }, + "ingress_policing_burst": { + "type": { + "key": { + "type": "integer", + "minInteger": 0 + } + } + }, + "ingress_policing_rate": { + "type": { + "key": { + "type": "integer", + "minInteger": 0 + } + } + }, + "lacp_current": { + "type": { + "key": { + "type": "boolean" + }, + "min": 0, + "max": 1 + }, + "ephemeral": true + }, + "link_resets": { + "type": { + "key": { + "type": "integer" + }, + "min": 0, + "max": 1 + }, + "ephemeral": true + }, + "link_speed": { + "type": { + "key": { + "type": "integer" + }, + "min": 0, + "max": 1 + }, + "ephemeral": true + }, + "link_state": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "up", + "down" + ] + ] + }, + "min": 0, + "max": 1 + }, + "ephemeral": true + }, + "lldp": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "mac": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "mac_in_use": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + }, + "ephemeral": true + }, + "mtu": { + "type": { + "key": { + "type": "integer" + }, + "min": 0, + "max": 1 + }, + "ephemeral": true + }, + "mtu_request": { + "type": { + "key": { + "type": "integer", + "minInteger": 1 + }, + "min": 0, + "max": 1 + } + }, + "name": { + "type": "string", + "mutable": false + }, + "ofport": { + "type": { + "key": { + "type": "integer" + }, + "min": 0, + "max": 1 + } + }, + "ofport_request": { + "type": { + "key": { + "type": "integer", + "minInteger": 1, + "maxInteger": 65279 + }, + "min": 0, + "max": 1 + } + }, + "options": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "other_config": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "statistics": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "integer" + }, + "min": 0, + "max": "unlimited" + }, + "ephemeral": true + }, + "status": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + }, + "ephemeral": true + }, + "type": { + "type": "string" + } + }, + "indexes": [ + [ + "name" + ] + ] + }, + "Manager": { + "columns": { + "connection_mode": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "in-band", + "out-of-band" + ] + ] + }, + "min": 0, + "max": 1 + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "inactivity_probe": { + "type": { + "key": { + "type": "integer" + }, + "min": 0, + "max": 1 + } + }, + "is_connected": { + "type": "boolean", + "ephemeral": true + }, + "max_backoff": { + "type": { + "key": { + "type": "integer", + "minInteger": 1000 + }, + "min": 0, + "max": 1 + } + }, + "other_config": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "status": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + }, + "ephemeral": true + }, + "target": { + "type": "string" + } + }, + "indexes": [ + [ + "target" + ] + ] + }, + "Mirror": { + "columns": { + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "name": { + "type": "string" + }, + "output_port": { + "type": { + "key": { + "type": "uuid", + "refTable": "Port", + "refType": "weak" + }, + "min": 0, + "max": 1 + } + }, + "output_vlan": { + "type": { + "key": { + "type": "integer", + "minInteger": 1, + "maxInteger": 4095 + }, + "min": 0, + "max": 1 + } + }, + "select_all": { + "type": "boolean" + }, + "select_dst_port": { + "type": { + "key": { + "type": "uuid", + "refTable": "Port", + "refType": "weak" + }, + "min": 0, + "max": "unlimited" + } + }, + "select_src_port": { + "type": { + "key": { + "type": "uuid", + "refTable": "Port", + "refType": "weak" + }, + "min": 0, + "max": "unlimited" + } + }, + "select_vlan": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 4095 + }, + "min": 0, + "max": 4096 + } + }, + "snaplen": { + "type": { + "key": { + "type": "integer", + "minInteger": 14, + "maxInteger": 65535 + }, + "min": 0, + "max": 1 + } + }, + "statistics": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "integer" + }, + "min": 0, + "max": "unlimited" + }, + "ephemeral": true + } + } + }, + "NetFlow": { + "columns": { + "active_timeout": { + "type": { + "key": { + "type": "integer", + "minInteger": -1 + } + } + }, + "add_id_to_interface": { + "type": "boolean" + }, + "engine_id": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 255 + }, + "min": 0, + "max": 1 + } + }, + "engine_type": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 255 + }, + "min": 0, + "max": 1 + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "targets": { + "type": { + "key": { + "type": "string" + }, + "min": 1, + "max": "unlimited" + } + } + } + }, + "Open_vSwitch": { + "columns": { + "bridges": { + "type": { + "key": { + "type": "uuid", + "refTable": "Bridge" + }, + "min": 0, + "max": "unlimited" + } + }, + "cur_cfg": { + "type": "integer" + }, + "datapath_types": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "datapaths": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "uuid", + "refTable": "Datapath" + }, + "min": 0, + "max": "unlimited" + } + }, + "db_version": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "dpdk_initialized": { + "type": "boolean" + }, + "dpdk_version": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "iface_types": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "manager_options": { + "type": { + "key": { + "type": "uuid", + "refTable": "Manager" + }, + "min": 0, + "max": "unlimited" + } + }, + "next_cfg": { + "type": "integer" + }, + "other_config": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "ovs_version": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "ssl": { + "type": { + "key": { + "type": "uuid", + "refTable": "SSL" + }, + "min": 0, + "max": 1 + } + }, + "statistics": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + }, + "ephemeral": true + }, + "system_type": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "system_version": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + } + } + }, + "Port": { + "columns": { + "bond_active_slave": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "bond_downdelay": { + "type": "integer" + }, + "bond_fake_iface": { + "type": "boolean" + }, + "bond_mode": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "balance-tcp", + "balance-slb", + "active-backup" + ] + ] + }, + "min": 0, + "max": 1 + } + }, + "bond_updelay": { + "type": "integer" + }, + "cvlans": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 4095 + }, + "min": 0, + "max": 4096 + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "fake_bridge": { + "type": "boolean" + }, + "interfaces": { + "type": { + "key": { + "type": "uuid", + "refTable": "Interface" + }, + "min": 1, + "max": "unlimited" + } + }, + "lacp": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "active", + "passive", + "off" + ] + ] + }, + "min": 0, + "max": 1 + } + }, + "mac": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "name": { + "type": "string", + "mutable": false + }, + "other_config": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "protected": { + "type": "boolean" + }, + "qos": { + "type": { + "key": { + "type": "uuid", + "refTable": "QoS" + }, + "min": 0, + "max": 1 + } + }, + "rstp_statistics": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "integer" + }, + "min": 0, + "max": "unlimited" + }, + "ephemeral": true + }, + "rstp_status": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + }, + "ephemeral": true + }, + "statistics": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "integer" + }, + "min": 0, + "max": "unlimited" + }, + "ephemeral": true + }, + "status": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + }, + "ephemeral": true + }, + "tag": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 4095 + }, + "min": 0, + "max": 1 + } + }, + "trunks": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 4095 + }, + "min": 0, + "max": 4096 + } + }, + "vlan_mode": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "trunk", + "access", + "native-tagged", + "native-untagged", + "dot1q-tunnel" + ] + ] + }, + "min": 0, + "max": 1 + } + } + }, + "indexes": [ + [ + "name" + ] + ] + }, + "QoS": { + "columns": { + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "other_config": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "queues": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 4294967295 + }, + "value": { + "type": "uuid", + "refTable": "Queue" + }, + "min": 0, + "max": "unlimited" + } + }, + "type": { + "type": "string" + } + } + }, + "Queue": { + "columns": { + "dscp": { + "type": { + "key": { + "type": "integer", + "minInteger": 0, + "maxInteger": 63 + }, + "min": 0, + "max": 1 + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "other_config": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + } + } + }, + "SSL": { + "columns": { + "bootstrap_ca_cert": { + "type": "boolean" + }, + "ca_cert": { + "type": "string" + }, + "certificate": { + "type": "string" + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "private_key": { + "type": "string" + } + } + }, + "sFlow": { + "columns": { + "agent": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "external_ids": { + "type": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "min": 0, + "max": "unlimited" + } + }, + "header": { + "type": { + "key": { + "type": "integer" + }, + "min": 0, + "max": 1 + } + }, + "polling": { + "type": { + "key": { + "type": "integer" + }, + "min": 0, + "max": 1 + } + }, + "sampling": { + "type": { + "key": { + "type": "integer" + }, + "min": 0, + "max": 1 + } + }, + "targets": { + "type": { + "key": { + "type": "string" + }, + "min": 1, + "max": "unlimited" + } + } + } + } + } +}` + +func Schema() ovsdb.DatabaseSchema { + var s ovsdb.DatabaseSchema + err := json.Unmarshal([]byte(schema), &s) + if err != nil { + panic(err) + } + return s +} diff --git a/internal/server/network/openvswitch/schema/ovs/netflow.go b/internal/server/network/openvswitch/schema/ovs/netflow.go new file mode 100644 index 00000000000..27eb9e716fd --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovs/netflow.go @@ -0,0 +1,17 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const NetFlowTable = "NetFlow" + +// NetFlow defines an object in NetFlow table +type NetFlow struct { + UUID string `ovsdb:"_uuid"` + ActiveTimeout int `ovsdb:"active_timeout"` + AddIDToInterface bool `ovsdb:"add_id_to_interface"` + EngineID *int `ovsdb:"engine_id"` + EngineType *int `ovsdb:"engine_type"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Targets []string `ovsdb:"targets"` +} diff --git a/internal/server/network/openvswitch/schema/ovs/open_vswitch.go b/internal/server/network/openvswitch/schema/ovs/open_vswitch.go new file mode 100644 index 00000000000..1b848d1d628 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovs/open_vswitch.go @@ -0,0 +1,28 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const OpenvSwitchTable = "Open_vSwitch" + +// OpenvSwitch defines an object in Open_vSwitch table +type OpenvSwitch struct { + UUID string `ovsdb:"_uuid"` + Bridges []string `ovsdb:"bridges"` + CurCfg int `ovsdb:"cur_cfg"` + DatapathTypes []string `ovsdb:"datapath_types"` + Datapaths map[string]string `ovsdb:"datapaths"` + DbVersion *string `ovsdb:"db_version"` + DpdkInitialized bool `ovsdb:"dpdk_initialized"` + DpdkVersion *string `ovsdb:"dpdk_version"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + IfaceTypes []string `ovsdb:"iface_types"` + ManagerOptions []string `ovsdb:"manager_options"` + NextCfg int `ovsdb:"next_cfg"` + OtherConfig map[string]string `ovsdb:"other_config"` + OVSVersion *string `ovsdb:"ovs_version"` + SSL *string `ovsdb:"ssl"` + Statistics map[string]string `ovsdb:"statistics"` + SystemType *string `ovsdb:"system_type"` + SystemVersion *string `ovsdb:"system_version"` +} diff --git a/internal/server/network/openvswitch/schema/ovs/port.go b/internal/server/network/openvswitch/schema/ovs/port.go new file mode 100644 index 00000000000..c77ee67c2f3 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovs/port.go @@ -0,0 +1,53 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const PortTable = "Port" + +type ( + PortBondMode = string + PortLACP = string + PortVLANMode = string +) + +var ( + PortBondModeBalanceTCP PortBondMode = "balance-tcp" + PortBondModeBalanceSLB PortBondMode = "balance-slb" + PortBondModeActiveBackup PortBondMode = "active-backup" + PortLACPActive PortLACP = "active" + PortLACPPassive PortLACP = "passive" + PortLACPOff PortLACP = "off" + PortVLANModeTrunk PortVLANMode = "trunk" + PortVLANModeAccess PortVLANMode = "access" + PortVLANModeNativeTagged PortVLANMode = "native-tagged" + PortVLANModeNativeUntagged PortVLANMode = "native-untagged" + PortVLANModeDot1qTunnel PortVLANMode = "dot1q-tunnel" +) + +// Port defines an object in Port table +type Port struct { + UUID string `ovsdb:"_uuid"` + BondActiveSlave *string `ovsdb:"bond_active_slave"` + BondDowndelay int `ovsdb:"bond_downdelay"` + BondFakeIface bool `ovsdb:"bond_fake_iface"` + BondMode *PortBondMode `ovsdb:"bond_mode"` + BondUpdelay int `ovsdb:"bond_updelay"` + CVLANs []int `ovsdb:"cvlans"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + FakeBridge bool `ovsdb:"fake_bridge"` + Interfaces []string `ovsdb:"interfaces"` + LACP *PortLACP `ovsdb:"lacp"` + MAC *string `ovsdb:"mac"` + Name string `ovsdb:"name"` + OtherConfig map[string]string `ovsdb:"other_config"` + Protected bool `ovsdb:"protected"` + QOS *string `ovsdb:"qos"` + RSTPStatistics map[string]int `ovsdb:"rstp_statistics"` + RSTPStatus map[string]string `ovsdb:"rstp_status"` + Statistics map[string]int `ovsdb:"statistics"` + Status map[string]string `ovsdb:"status"` + Tag *int `ovsdb:"tag"` + Trunks []int `ovsdb:"trunks"` + VLANMode *PortVLANMode `ovsdb:"vlan_mode"` +} diff --git a/internal/server/network/openvswitch/schema/ovs/qos.go b/internal/server/network/openvswitch/schema/ovs/qos.go new file mode 100644 index 00000000000..656abf67e5a --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovs/qos.go @@ -0,0 +1,15 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const QoSTable = "QoS" + +// QoS defines an object in QoS table +type QoS struct { + UUID string `ovsdb:"_uuid"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + OtherConfig map[string]string `ovsdb:"other_config"` + Queues map[int]string `ovsdb:"queues"` + Type string `ovsdb:"type"` +} diff --git a/internal/server/network/openvswitch/schema/ovs/queue.go b/internal/server/network/openvswitch/schema/ovs/queue.go new file mode 100644 index 00000000000..e67f399bdae --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovs/queue.go @@ -0,0 +1,14 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const QueueTable = "Queue" + +// Queue defines an object in Queue table +type Queue struct { + UUID string `ovsdb:"_uuid"` + DSCP *int `ovsdb:"dscp"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + OtherConfig map[string]string `ovsdb:"other_config"` +} diff --git a/internal/server/network/openvswitch/schema/ovs/sflow.go b/internal/server/network/openvswitch/schema/ovs/sflow.go new file mode 100644 index 00000000000..c7a7a6d7cee --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovs/sflow.go @@ -0,0 +1,17 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const SFlowTable = "sFlow" + +// SFlow defines an object in sFlow table +type SFlow struct { + UUID string `ovsdb:"_uuid"` + Agent *string `ovsdb:"agent"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + Header *int `ovsdb:"header"` + Polling *int `ovsdb:"polling"` + Sampling *int `ovsdb:"sampling"` + Targets []string `ovsdb:"targets"` +} diff --git a/internal/server/network/openvswitch/schema/ovs/ssl.go b/internal/server/network/openvswitch/schema/ovs/ssl.go new file mode 100644 index 00000000000..306350bfb19 --- /dev/null +++ b/internal/server/network/openvswitch/schema/ovs/ssl.go @@ -0,0 +1,16 @@ +// Code generated by "libovsdb.modelgen" +// DO NOT EDIT. + +package ovsmodel + +const SSLTable = "SSL" + +// SSL defines an object in SSL table +type SSL struct { + UUID string `ovsdb:"_uuid"` + BootstrapCaCert bool `ovsdb:"bootstrap_ca_cert"` + CaCert string `ovsdb:"ca_cert"` + Certificate string `ovsdb:"certificate"` + ExternalIDs map[string]string `ovsdb:"external_ids"` + PrivateKey string `ovsdb:"private_key"` +} From afc32c52ec6291f61ff1b880756d580010bd2c3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Mon, 18 Dec 2023 13:20:23 -0500 Subject: [PATCH 04/38] incusd/network/openvswitch: Remove unused functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- internal/server/network/openvswitch/ovn.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/internal/server/network/openvswitch/ovn.go b/internal/server/network/openvswitch/ovn.go index 17cbfcd6a89..4dd66b77cbf 100644 --- a/internal/server/network/openvswitch/ovn.go +++ b/internal/server/network/openvswitch/ovn.go @@ -256,11 +256,6 @@ type OVN struct { sslClientKey string } -// SetNorthboundDBAddress sets the address that runs the OVN northbound databases. -func (o *OVN) SetNorthboundDBAddress(addr string) { - o.nbDBAddr = addr -} - // getNorthboundDB returns connection string to use for northbound database. func (o *OVN) getNorthboundDB() string { if o.nbDBAddr == "" { @@ -270,11 +265,6 @@ func (o *OVN) getNorthboundDB() string { return o.nbDBAddr } -// SetSouthboundDBAddress sets the address that runs the OVN northbound databases. -func (o *OVN) SetSouthboundDBAddress(addr string) { - o.sbDBAddr = addr -} - // getSouthboundDB returns connection string to use for northbound database. func (o *OVN) getSouthboundDB() string { if o.sbDBAddr == "" { From d2bfba75565faaed5e43f95152d8ab8da8725a8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Mon, 18 Dec 2023 14:06:49 -0500 Subject: [PATCH 05/38] incusd/network/openvswitch: Remove useless code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- internal/server/network/openvswitch/ovn.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/internal/server/network/openvswitch/ovn.go b/internal/server/network/openvswitch/ovn.go index 4dd66b77cbf..12a5bcf7c16 100644 --- a/internal/server/network/openvswitch/ovn.go +++ b/internal/server/network/openvswitch/ovn.go @@ -293,10 +293,6 @@ func (o *OVN) xbctl(southbound bool, extraArgs ...string) (string, error) { cmd = "ovn-sbctl" } - if strings.HasPrefix(dbAddr, "unix:") { - dbAddr = fmt.Sprintf("unix:%s", strings.TrimPrefix(dbAddr, "unix:")) - } - // Figure out args. args := []string{"--timeout=10", "--db", dbAddr} From fd03aea006ba1c8141a58d215168b473e4090ea7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Mon, 18 Dec 2023 13:23:26 -0500 Subject: [PATCH 06/38] incusd/network/openvswitch: Split OVN logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- internal/server/network/openvswitch/ovn.go | 2201 ---------------- .../server/network/openvswitch/ovn_actions.go | 2208 +++++++++++++++++ 2 files changed, 2208 insertions(+), 2201 deletions(-) create mode 100644 internal/server/network/openvswitch/ovn_actions.go diff --git a/internal/server/network/openvswitch/ovn.go b/internal/server/network/openvswitch/ovn.go index 12a5bcf7c16..9ab82bfa2d7 100644 --- a/internal/server/network/openvswitch/ovn.go +++ b/internal/server/network/openvswitch/ovn.go @@ -3,183 +3,14 @@ package openvswitch import ( "context" "fmt" - "net" "os" - "strconv" "strings" - "time" - "github.com/lxc/incus/internal/iprange" "github.com/lxc/incus/internal/linux" "github.com/lxc/incus/internal/server/state" "github.com/lxc/incus/shared/subprocess" - "github.com/lxc/incus/shared/util" ) -// OVNRouter OVN router name. -type OVNRouter string - -// OVNRouterPort OVN router port name. -type OVNRouterPort string - -// OVNSwitch OVN switch name. -type OVNSwitch string - -// OVNSwitchPort OVN switch port name. -type OVNSwitchPort string - -// OVNSwitchPortUUID OVN switch port UUID. -type OVNSwitchPortUUID string - -// OVNChassisGroup OVN HA chassis group name. -type OVNChassisGroup string - -// OVNDNSUUID OVN DNS record UUID. -type OVNDNSUUID string - -// OVNDHCPOptionsUUID DHCP Options set UUID. -type OVNDHCPOptionsUUID string - -// OVNPortGroup OVN port group name. -type OVNPortGroup string - -// OVNPortGroupUUID OVN port group UUID. -type OVNPortGroupUUID string - -// OVNLoadBalancer OVN load balancer name. -type OVNLoadBalancer string - -// OVNAddressSet OVN address set for ACLs. -type OVNAddressSet string - -// OVNIPAllocationOpts defines IP allocation settings that can be applied to a logical switch. -type OVNIPAllocationOpts struct { - PrefixIPv4 *net.IPNet - PrefixIPv6 *net.IPNet - ExcludeIPv4 []iprange.Range -} - -// OVNIPv6AddressMode IPv6 router advertisement address mode. -type OVNIPv6AddressMode string - -// OVNIPv6AddressModeSLAAC IPv6 SLAAC mode. -const OVNIPv6AddressModeSLAAC OVNIPv6AddressMode = "slaac" - -// OVNIPv6AddressModeDHCPStateful IPv6 DHCPv6 stateful mode. -const OVNIPv6AddressModeDHCPStateful OVNIPv6AddressMode = "dhcpv6_stateful" - -// OVNIPv6AddressModeDHCPStateless IPv6 DHCPv6 stateless mode. -const OVNIPv6AddressModeDHCPStateless OVNIPv6AddressMode = "dhcpv6_stateless" - -// OVN External ID names used by Incus. -const ovnExtIDIncusSwitch = "incus_switch" -const ovnExtIDIncusSwitchPort = "incus_switch_port" -const ovnExtIDIncusProjectID = "incus_project_id" -const ovnExtIDIncusPortGroup = "incus_port_group" -const ovnExtIDIncusLocation = "incus_location" - -// OVNIPv6RAOpts IPv6 router advertisements options that can be applied to a router. -type OVNIPv6RAOpts struct { - SendPeriodic bool - AddressMode OVNIPv6AddressMode - MinInterval time.Duration - MaxInterval time.Duration - RecursiveDNSServer net.IP - DNSSearchList []string - MTU uint32 -} - -// OVNDHCPOptsSet is an existing DHCP options set in the northbound database. -type OVNDHCPOptsSet struct { - UUID OVNDHCPOptionsUUID - CIDR *net.IPNet -} - -// OVNDHCPv4Opts IPv4 DHCP options that can be applied to a switch port. -type OVNDHCPv4Opts struct { - ServerID net.IP - ServerMAC net.HardwareAddr - Router net.IP - RecursiveDNSServer []net.IP - DomainName string - LeaseTime time.Duration - MTU uint32 - Netmask string -} - -// OVNDHCPv6Opts IPv6 DHCP option set that can be created (and then applied to a switch port by resulting ID). -type OVNDHCPv6Opts struct { - ServerID net.HardwareAddr - RecursiveDNSServer []net.IP - DNSSearchList []string -} - -// OVNSwitchPortOpts options that can be applied to a swich port. -type OVNSwitchPortOpts struct { - MAC net.HardwareAddr // Optional, if nil will be set to dynamic. - IPs []net.IP // Optional, if empty IPs will be set to dynamic. - DHCPv4OptsID OVNDHCPOptionsUUID // Optional, if empty, no DHCPv4 enabled on port. - DHCPv6OptsID OVNDHCPOptionsUUID // Optional, if empty, no DHCPv6 enabled on port. - Parent OVNSwitchPort // Optional, if set a nested port is created. - VLAN uint16 // Optional, use with Parent to request a specific VLAN for nested port. - Location string // Optional, use to indicate the name of the server this port is bound to. -} - -// OVNACLRule represents an ACL rule that can be added to a logical switch or port group. -type OVNACLRule struct { - Direction string // Either "from-lport" or "to-lport". - Action string // Either "allow-related", "allow", "drop", or "reject". - Match string // Match criteria. See OVN Southbound database's Logical_Flow table match column usage. - Priority int // Priority (between 0 and 32767, inclusive). Higher values take precedence. - Log bool // Whether or not to log matched packets. - LogName string // Log label name (requires Log be true). -} - -// OVNLoadBalancerTarget represents an OVN load balancer Virtual IP target. -type OVNLoadBalancerTarget struct { - Address net.IP - Port uint64 -} - -// OVNLoadBalancerVIP represents a OVN load balancer Virtual IP entry. -type OVNLoadBalancerVIP struct { - Protocol string // Either "tcp" or "udp". But only applies to port based VIPs. - ListenAddress net.IP - ListenPort uint64 - Targets []OVNLoadBalancerTarget -} - -// OVNRouterRoute represents a static route added to a logical router. -type OVNRouterRoute struct { - Prefix net.IPNet - NextHop net.IP - Port OVNRouterPort - Discard bool -} - -// OVNRouterPolicy represents a router policy. -type OVNRouterPolicy struct { - Priority int - Match string - Action string - NextHop net.IP -} - -// OVNRouterPeering represents a the configuration of a peering connection between two OVN logical routers. -type OVNRouterPeering struct { - LocalRouter OVNRouter - LocalRouterPort OVNRouterPort - LocalRouterPortMAC net.HardwareAddr - LocalRouterPortIPs []net.IPNet - LocalRouterRoutes []net.IPNet - - TargetRouter OVNRouter - TargetRouterPort OVNRouterPort - TargetRouterPortMAC net.HardwareAddr - TargetRouterPortIPs []net.IPNet - TargetRouterRoutes []net.IPNet -} - // NewOVN initialises new OVN client wrapper with the connection set in network.ovn.northbound_connection config. func NewOVN(s *state.State) (*OVN, error) { // Get database connection strings. @@ -336,2035 +167,3 @@ func (o *OVN) xbctl(southbound bool, extraArgs ...string) (string, error) { args = append(args, extraArgs...) return subprocess.RunCommandInheritFds(context.Background(), files, cmd, args...) } - -// LogicalRouterAdd adds a named logical router. -func (o *OVN) LogicalRouterAdd(routerName OVNRouter, mayExist bool) error { - args := []string{} - - if mayExist { - args = append(args, "--may-exist") - } - - _, err := o.nbctl(append(args, "lr-add", string(routerName))...) - if err != nil { - return err - } - - return nil -} - -// LogicalRouterDelete deletes a named logical router. -func (o OVN) LogicalRouterDelete(routerName OVNRouter) error { - _, err := o.nbctl("--if-exists", "lr-del", string(routerName)) - if err != nil { - return err - } - - return nil -} - -// LogicalRouterSNATAdd adds an SNAT rule to a logical router to translate packets from intNet to extIP. -func (o *OVN) LogicalRouterSNATAdd(routerName OVNRouter, intNet *net.IPNet, extIP net.IP, mayExist bool) error { - args := []string{} - - if mayExist { - args = append(args, "--if-exists", "lr-nat-del", string(routerName), "snat", extIP.String(), "--") - } - - _, err := o.nbctl(append(args, "lr-nat-add", string(routerName), "snat", extIP.String(), intNet.String())...) - if err != nil { - return err - } - - return nil -} - -// LogicalRouterDNATSNATDeleteAll deletes all DNAT_AND_SNAT rules from a logical router. -func (o *OVN) LogicalRouterDNATSNATDeleteAll(routerName OVNRouter) error { - _, err := o.nbctl("--if-exists", "lr-nat-del", string(routerName), "dnat_and_snat") - if err != nil { - return err - } - - return nil -} - -// LogicalRouterSNATDeleteAll deletes all SNAT rules from a logical router. -func (o *OVN) LogicalRouterSNATDeleteAll(routerName OVNRouter) error { - _, err := o.nbctl("--if-exists", "lr-nat-del", string(routerName), "snat") - if err != nil { - return err - } - - return nil -} - -// LogicalRouterDNATSNATAdd adds a DNAT_AND_SNAT rule to a logical router to translate packets from extIP to intIP. -func (o *OVN) LogicalRouterDNATSNATAdd(routerName OVNRouter, extIP net.IP, intIP net.IP, stateless bool, mayExist bool) error { - if mayExist { - // There appears to be a bug in ovn-nbctl where running lr-nat-del as part of the same command as - // lr-nat-add doesn't take account the changes by lr-nat-del, and so you can end up with errors - // if a NAT entry already exists. So we run them as separate command invocations. - // There can be left over dnat_and_snat entries if an instance was stopped when the ovn-nb DB - // was not reachable. - _, err := o.nbctl("--if-exists", "lr-nat-del", string(routerName), "dnat_and_snat", extIP.String()) - if err != nil { - return err - } - } - - args := []string{} - - if stateless { - args = append(args, "--stateless") - } - - _, err := o.nbctl(append(args, "lr-nat-add", string(routerName), "dnat_and_snat", extIP.String(), intIP.String())...) - if err != nil { - return err - } - - return nil -} - -// LogicalRouterDNATSNATDelete deletes a DNAT_AND_SNAT rule from a logical router. -func (o *OVN) LogicalRouterDNATSNATDelete(routerName OVNRouter, extIPs ...net.IP) error { - args := []string{} - - for _, extIP := range extIPs { - if len(args) > 0 { - args = append(args, "--") - } - - args = append(args, "--if-exists", "lr-nat-del", string(routerName), "dnat_and_snat", extIP.String()) - } - - _, err := o.nbctl(args...) - if err != nil { - return err - } - - return nil -} - -// LogicalRouterRouteAdd adds a static route to the logical router. -func (o *OVN) LogicalRouterRouteAdd(routerName OVNRouter, mayExist bool, routes ...OVNRouterRoute) error { - args := []string{} - - for _, route := range routes { - if len(args) > 0 { - args = append(args, "--") - } - - if mayExist { - args = append(args, "--may-exist") - } - - args = append(args, "lr-route-add", string(routerName), route.Prefix.String()) - - if route.Discard { - args = append(args, "discard") - } else { - args = append(args, route.NextHop.String()) - } - - if route.Port != "" { - args = append(args, string(route.Port)) - } - } - - if len(args) > 0 { - _, err := o.nbctl(args...) - if err != nil { - return err - } - } - - return nil -} - -// LogicalRouterRouteDelete deletes a static route from the logical router. -func (o *OVN) LogicalRouterRouteDelete(routerName OVNRouter, prefixes ...net.IPNet) error { - args := []string{} - - // Delete specific destination routes on router. - for _, prefix := range prefixes { - if len(args) > 0 { - args = append(args, "--") - } - - args = append(args, "--if-exists", "lr-route-del", string(routerName), prefix.String()) - } - - _, err := o.nbctl(args...) - if err != nil { - return err - } - - return nil -} - -// LogicalRouterPortAdd adds a named logical router port to a logical router. -func (o *OVN) LogicalRouterPortAdd(routerName OVNRouter, portName OVNRouterPort, mac net.HardwareAddr, gatewayMTU uint32, ipAddr []*net.IPNet, mayExist bool) error { - if mayExist { - // Check if it exists and update addresses. - _, err := o.nbctl("list", "Logical_Router_Port", string(portName)) - if err == nil { - // Router port exists. - ips := make([]string, 0, len(ipAddr)) - for _, ip := range ipAddr { - ips = append(ips, ip.String()) - } - - _, err := o.nbctl("set", "Logical_Router_Port", string(portName), - fmt.Sprintf(`networks="%s"`, strings.Join(ips, `","`)), - fmt.Sprintf(`mac="%s"`, mac.String()), - fmt.Sprintf("options:gateway_mtu=%d", gatewayMTU), - ) - if err != nil { - return err - } - - return nil - } - } - - args := []string{"lrp-add", string(routerName), string(portName), mac.String()} - for _, ipNet := range ipAddr { - args = append(args, ipNet.String()) - } - - args = append(args, "--", "set", "Logical_Router_Port", string(portName), - fmt.Sprintf(`options:gateway_mtu=%d`, gatewayMTU), - ) - - _, err := o.nbctl(args...) - if err != nil { - return err - } - - return nil -} - -// LogicalRouterPortDelete deletes a named logical router port from a logical router. -func (o *OVN) LogicalRouterPortDelete(portName OVNRouterPort) error { - _, err := o.nbctl("--if-exists", "lrp-del", string(portName)) - if err != nil { - return err - } - - return nil -} - -// LogicalRouterPortSetIPv6Advertisements sets the IPv6 router advertisement options on a router port. -func (o *OVN) LogicalRouterPortSetIPv6Advertisements(portName OVNRouterPort, opts *OVNIPv6RAOpts) error { - args := []string{"set", "logical_router_port", string(portName), - fmt.Sprintf("ipv6_ra_configs:send_periodic=%t", opts.SendPeriodic), - } - - var removeRAConfigKeys []string - - if opts.AddressMode != "" { - args = append(args, fmt.Sprintf("ipv6_ra_configs:address_mode=%s", string(opts.AddressMode))) - } else { - removeRAConfigKeys = append(removeRAConfigKeys, "address_mode") - } - - if opts.MaxInterval > 0 { - args = append(args, fmt.Sprintf("ipv6_ra_configs:max_interval=%d", opts.MaxInterval/time.Second)) - } else { - removeRAConfigKeys = append(removeRAConfigKeys, "max_interval") - } - - if opts.MinInterval > 0 { - args = append(args, fmt.Sprintf("ipv6_ra_configs:min_interval=%d", opts.MinInterval/time.Second)) - } else { - removeRAConfigKeys = append(removeRAConfigKeys, "min_interval") - } - - if opts.MTU > 0 { - args = append(args, fmt.Sprintf("ipv6_ra_configs:mtu=%d", opts.MTU)) - } else { - removeRAConfigKeys = append(removeRAConfigKeys, "mtu") - } - - if len(opts.DNSSearchList) > 0 { - args = append(args, fmt.Sprintf("ipv6_ra_configs:dnssl=%s", strings.Join(opts.DNSSearchList, ","))) - } else { - removeRAConfigKeys = append(removeRAConfigKeys, "dnssl") - } - - if opts.RecursiveDNSServer != nil { - args = append(args, fmt.Sprintf("ipv6_ra_configs:rdnss=%s", opts.RecursiveDNSServer.String())) - } else { - removeRAConfigKeys = append(removeRAConfigKeys, "rdnss") - } - - // Clear any unused keys first. - if len(removeRAConfigKeys) > 0 { - removeArgs := append([]string{"remove", "logical_router_port", string(portName), "ipv6_ra_configs"}, removeRAConfigKeys...) - _, err := o.nbctl(removeArgs...) - if err != nil { - return err - } - } - - // Configure IPv6 Router Advertisements. - _, err := o.nbctl(args...) - if err != nil { - return err - } - - return nil -} - -// LogicalRouterPortDeleteIPv6Advertisements removes the IPv6 RA announcement settings from a router port. -func (o *OVN) LogicalRouterPortDeleteIPv6Advertisements(portName OVNRouterPort) error { - // Delete IPv6 Router Advertisements. - _, err := o.nbctl("clear", "logical_router_port", string(portName), "ipv6_ra_configs") - if err != nil { - return err - } - - return nil -} - -// LogicalRouterPortLinkChassisGroup links a logical router port to a HA chassis group. -func (o *OVN) LogicalRouterPortLinkChassisGroup(portName OVNRouterPort, haChassisGroupName OVNChassisGroup) error { - chassisGroupID, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid", "find", "ha_chassis_group", fmt.Sprintf("name=%s", haChassisGroupName)) - if err != nil { - return err - } - - chassisGroupID = strings.TrimSpace(chassisGroupID) - - if chassisGroupID == "" { - return fmt.Errorf("Chassis group not found") - } - - _, err = o.nbctl("set", "logical_router_port", string(portName), fmt.Sprintf("ha_chassis_group=%s", chassisGroupID)) - if err != nil { - return err - } - - return nil -} - -// LogicalSwitchAdd adds a named logical switch. -// If mayExist is true, then an existing resource of the same name is not treated as an error. -func (o *OVN) LogicalSwitchAdd(switchName OVNSwitch, mayExist bool) error { - args := []string{} - - if mayExist { - args = append(args, "--may-exist") - } - - args = append(args, "ls-add", string(switchName)) - _, err := o.nbctl(args...) - if err != nil { - return err - } - - return nil -} - -// LogicalSwitchDelete deletes a named logical switch. -func (o *OVN) LogicalSwitchDelete(switchName OVNSwitch) error { - args := []string{"--if-exists", "ls-del", string(switchName)} - - assocPortGroups, err := o.logicalSwitchFindAssociatedPortGroups(switchName) - if err != nil { - return err - } - - for _, assocPortGroup := range assocPortGroups { - args = append(args, "--", "destroy", "port_group", string(assocPortGroup)) - } - - _, err = o.nbctl(args...) - if err != nil { - return err - } - - // Remove any existing DHCP options associated to switch. - deleteDHCPRecords, err := o.LogicalSwitchDHCPOptionsGet(switchName) - if err != nil { - return err - } - - if len(deleteDHCPRecords) > 0 { - deleteDHCPUUIDs := make([]OVNDHCPOptionsUUID, 0, len(deleteDHCPRecords)) - for _, deleteDHCPRecord := range deleteDHCPRecords { - deleteDHCPUUIDs = append(deleteDHCPUUIDs, deleteDHCPRecord.UUID) - } - - err = o.LogicalSwitchDHCPOptionsDelete(switchName, deleteDHCPUUIDs...) - if err != nil { - return err - } - } - - err = o.logicalSwitchDNSRecordsDelete(switchName) - if err != nil { - return err - } - - return nil -} - -// logicalSwitchFindAssociatedPortGroups finds the port groups that are associated to the switch specified. -func (o *OVN) logicalSwitchFindAssociatedPortGroups(switchName OVNSwitch) ([]OVNPortGroup, error) { - output, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=name", "find", "port_group", - fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName), - ) - if err != nil { - return nil, err - } - - lines := util.SplitNTrimSpace(strings.TrimSpace(output), "\n", -1, true) - portGroups := make([]OVNPortGroup, 0, len(lines)) - - for _, line := range lines { - portGroups = append(portGroups, OVNPortGroup(line)) - } - - return portGroups, nil -} - -// logicalSwitchParseExcludeIPs parses the ips into OVN exclude_ips format. -func (o *OVN) logicalSwitchParseExcludeIPs(ips []iprange.Range) ([]string, error) { - excludeIPs := make([]string, 0, len(ips)) - for _, v := range ips { - if v.Start == nil || v.Start.To4() == nil { - return nil, fmt.Errorf("Invalid exclude IPv4 range start address") - } else if v.End == nil { - excludeIPs = append(excludeIPs, v.Start.String()) - } else { - if v.End != nil && v.End.To4() == nil { - return nil, fmt.Errorf("Invalid exclude IPv4 range end address") - } - - excludeIPs = append(excludeIPs, fmt.Sprintf("%s..%s", v.Start.String(), v.End.String())) - } - } - - return excludeIPs, nil -} - -// LogicalSwitchSetIPAllocation sets the IP allocation config on the logical switch. -func (o *OVN) LogicalSwitchSetIPAllocation(switchName OVNSwitch, opts *OVNIPAllocationOpts) error { - var removeOtherConfigKeys []string - args := []string{"set", "logical_switch", string(switchName)} - - if opts.PrefixIPv4 != nil { - args = append(args, fmt.Sprintf("other_config:subnet=%s", opts.PrefixIPv4.String())) - } else { - removeOtherConfigKeys = append(removeOtherConfigKeys, "subnet") - } - - if opts.PrefixIPv6 != nil { - args = append(args, fmt.Sprintf("other_config:ipv6_prefix=%s", opts.PrefixIPv6.String())) - } else { - removeOtherConfigKeys = append(removeOtherConfigKeys, "ipv6_prefix") - } - - if len(opts.ExcludeIPv4) > 0 { - excludeIPs, err := o.logicalSwitchParseExcludeIPs(opts.ExcludeIPv4) - if err != nil { - return err - } - - args = append(args, fmt.Sprintf("other_config:exclude_ips=%s", strings.Join(excludeIPs, " "))) - } else { - removeOtherConfigKeys = append(removeOtherConfigKeys, "exclude_ips") - } - - // Clear any unused keys first. - if len(removeOtherConfigKeys) > 0 { - removeArgs := append([]string{"remove", "logical_switch", string(switchName), "other_config"}, removeOtherConfigKeys...) - _, err := o.nbctl(removeArgs...) - if err != nil { - return err - } - } - - // Only run command if at least one setting is specified. - if len(args) > 3 { - _, err := o.nbctl(args...) - if err != nil { - return err - } - } - - return nil -} - -// LogicalSwitchDHCPv4RevervationsSet sets the DHCPv4 IP reservations. -func (o *OVN) LogicalSwitchDHCPv4RevervationsSet(switchName OVNSwitch, reservedIPs []iprange.Range) error { - var removeOtherConfigKeys []string - args := []string{"set", "logical_switch", string(switchName)} - - if len(reservedIPs) > 0 { - excludeIPs, err := o.logicalSwitchParseExcludeIPs(reservedIPs) - if err != nil { - return err - } - - args = append(args, fmt.Sprintf("other_config:exclude_ips=%s", strings.Join(excludeIPs, " "))) - } else { - removeOtherConfigKeys = append(removeOtherConfigKeys, "exclude_ips") - } - - // Clear any unused keys first. - if len(removeOtherConfigKeys) > 0 { - removeArgs := append([]string{"remove", "logical_switch", string(switchName), "other_config"}, removeOtherConfigKeys...) - _, err := o.nbctl(removeArgs...) - if err != nil { - return err - } - } - - // Only run command if at least one setting is specified. - if len(args) > 3 { - _, err := o.nbctl(args...) - if err != nil { - return err - } - } - - return nil -} - -// LogicalSwitchDHCPv4RevervationsGet gets the DHCPv4 IP reservations. -func (o *OVN) LogicalSwitchDHCPv4RevervationsGet(switchName OVNSwitch) ([]iprange.Range, error) { - excludeIPsRaw, err := o.nbctl("--if-exists", "get", "logical_switch", string(switchName), "other_config:exclude_ips") - if err != nil { - return nil, err - } - - excludeIPsRaw = strings.TrimSpace(excludeIPsRaw) - - // Check if no dynamic IPs set. - if excludeIPsRaw == "" || excludeIPsRaw == "[]" { - return []iprange.Range{}, nil - } - - excludeIPsRaw, err = unquote(excludeIPsRaw) - if err != nil { - return nil, fmt.Errorf("Failed unquoting exclude_ips: %w", err) - } - - excludeIPsParts := util.SplitNTrimSpace(strings.TrimSpace(excludeIPsRaw), " ", -1, true) - excludeIPs := make([]iprange.Range, 0, len(excludeIPsParts)) - - for _, excludeIPsPart := range excludeIPsParts { - ip := net.ParseIP(excludeIPsPart) // Check if single IP part. - if ip == nil { - // Check if IP range part. - start, end, found := strings.Cut(excludeIPsPart, "..") - if found { - startIP := net.ParseIP(start) - endIP := net.ParseIP(end) - - if startIP == nil || endIP == nil { - return nil, fmt.Errorf("Invalid exclude_ips range: %q", excludeIPsPart) - } - - // Add range IP part to list. - excludeIPs = append(excludeIPs, iprange.Range{Start: startIP, End: endIP}) - } else { - return nil, fmt.Errorf("Unrecognised exclude_ips part: %q", excludeIPsPart) - } - } else { - // Add single IP part to list. - excludeIPs = append(excludeIPs, iprange.Range{Start: ip}) - } - } - - return excludeIPs, nil -} - -// LogicalSwitchDHCPv4OptionsSet creates or updates a DHCPv4 option set associated with the specified switchName -// and subnet. If uuid is non-empty then the record that exists with that ID is updated, otherwise a new record -// is created. -func (o *OVN) LogicalSwitchDHCPv4OptionsSet(switchName OVNSwitch, uuid OVNDHCPOptionsUUID, subnet *net.IPNet, opts *OVNDHCPv4Opts) error { - var err error - - if uuid != "" { - _, err = o.nbctl("set", "dhcp_option", string(uuid), - fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName), - fmt.Sprintf("cidr=%s", subnet.String()), - ) - if err != nil { - return err - } - } else { - uuidRaw, err := o.nbctl("create", "dhcp_option", - fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName), - fmt.Sprintf("cidr=%s", subnet.String()), - ) - if err != nil { - return err - } - - uuid = OVNDHCPOptionsUUID(strings.TrimSpace(uuidRaw)) - } - - // We have to use dhcp-options-set-options rather than the command above as its the only way to allow the - // domain_name option to be properly escaped. - args := []string{"dhcp-options-set-options", string(uuid), - fmt.Sprintf("server_id=%s", opts.ServerID.String()), - fmt.Sprintf("server_mac=%s", opts.ServerMAC.String()), - fmt.Sprintf("lease_time=%d", opts.LeaseTime/time.Second), - } - - if opts.Router != nil { - args = append(args, fmt.Sprintf("router=%s", opts.Router.String())) - } - - if opts.RecursiveDNSServer != nil { - nsIPs := make([]string, 0, len(opts.RecursiveDNSServer)) - for _, nsIP := range opts.RecursiveDNSServer { - if nsIP.To4() == nil { - continue // Only include IPv4 addresses. - } - - nsIPs = append(nsIPs, nsIP.String()) - } - - args = append(args, fmt.Sprintf("dns_server={%s}", strings.Join(nsIPs, ","))) - } - - if opts.DomainName != "" { - // Special quoting to allow domain names. - args = append(args, fmt.Sprintf(`domain_name="%s"`, opts.DomainName)) - } - - if opts.MTU > 0 { - args = append(args, fmt.Sprintf("mtu=%d", opts.MTU)) - } - - if opts.Netmask != "" { - args = append(args, fmt.Sprintf("netmask=%s", opts.Netmask)) - } - - _, err = o.nbctl(args...) - if err != nil { - return err - } - - return nil -} - -// LogicalSwitchDHCPv6OptionsSet creates or updates a DHCPv6 option set associated with the specified switchName -// and subnet. If uuid is non-empty then the record that exists with that ID is updated, otherwise a new record -// is created. -func (o *OVN) LogicalSwitchDHCPv6OptionsSet(switchName OVNSwitch, uuid OVNDHCPOptionsUUID, subnet *net.IPNet, opts *OVNDHCPv6Opts) error { - var err error - - if uuid != "" { - _, err = o.nbctl("set", "dhcp_option", string(uuid), - fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName), - fmt.Sprintf(`cidr="%s"`, subnet.String()), // Special quoting to allow IPv6 address. - ) - if err != nil { - return err - } - } else { - uuidRaw, err := o.nbctl("create", "dhcp_option", - fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName), - fmt.Sprintf(`cidr="%s"`, subnet.String()), // Special quoting to allow IPv6 address. - ) - if err != nil { - return err - } - - uuid = OVNDHCPOptionsUUID(strings.TrimSpace(uuidRaw)) - } - - // We have to use dhcp-options-set-options rather than the command above as its the only way to allow the - // domain_name option to be properly escaped. - args := []string{"dhcp-options-set-options", string(uuid), - fmt.Sprintf("server_id=%s", opts.ServerID.String()), - } - - if len(opts.DNSSearchList) > 0 { - // Special quoting to allow domain names. - args = append(args, fmt.Sprintf(`domain_search="%s"`, strings.Join(opts.DNSSearchList, ","))) - } - - if opts.RecursiveDNSServer != nil { - nsIPs := make([]string, 0, len(opts.RecursiveDNSServer)) - for _, nsIP := range opts.RecursiveDNSServer { - if nsIP.To4() != nil { - continue // Only include IPv6 addresses. - } - - nsIPs = append(nsIPs, nsIP.String()) - } - - args = append(args, fmt.Sprintf("dns_server={%s}", strings.Join(nsIPs, ","))) - } - - _, err = o.nbctl(args...) - if err != nil { - return err - } - - return nil -} - -// LogicalSwitchDHCPOptionsGet retrieves the existing DHCP options defined for a logical switch. -func (o *OVN) LogicalSwitchDHCPOptionsGet(switchName OVNSwitch) ([]OVNDHCPOptsSet, error) { - output, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid,cidr", "find", "dhcp_options", - fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName), - ) - if err != nil { - return nil, err - } - - colCount := 2 - dhcpOpts := []OVNDHCPOptsSet{} - output = strings.TrimSpace(output) - if output != "" { - for _, row := range strings.Split(output, "\n") { - rowParts := strings.SplitN(row, ",", colCount) - if len(rowParts) < colCount { - return nil, fmt.Errorf("Too few columns in output") - } - - _, cidr, err := net.ParseCIDR(rowParts[1]) - if err != nil { - return nil, err - } - - dhcpOpts = append(dhcpOpts, OVNDHCPOptsSet{ - UUID: OVNDHCPOptionsUUID(rowParts[0]), - CIDR: cidr, - }) - } - } - - return dhcpOpts, nil -} - -// LogicalSwitchDHCPOptionsDelete deletes the specified DHCP options defined for a switch. -func (o *OVN) LogicalSwitchDHCPOptionsDelete(switchName OVNSwitch, uuids ...OVNDHCPOptionsUUID) error { - args := []string{} - - for _, uuid := range uuids { - if len(args) > 0 { - args = append(args, "--") - } - - args = append(args, "destroy", "dhcp_options", string(uuid)) - } - - _, err := o.nbctl(args...) - if err != nil { - return err - } - - return nil -} - -// logicalSwitchDNSRecordsDelete deletes any DNS records defined for a switch. -func (o *OVN) logicalSwitchDNSRecordsDelete(switchName OVNSwitch) error { - uuids, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid", "find", "dns", - fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName), - ) - if err != nil { - return err - } - - args := []string{} - - for _, uuid := range util.SplitNTrimSpace(strings.TrimSpace(uuids), "\n", -1, true) { - if len(args) > 0 { - args = append(args, "--") - } - - args = append(args, "destroy", "dns", uuid) - } - - if len(args) > 0 { - _, err = o.nbctl(args...) - if err != nil { - return err - } - } - - return nil -} - -// LogicalSwitchSetACLRules applies a set of rules to the specified logical switch. Any existing rules are removed. -func (o *OVN) LogicalSwitchSetACLRules(switchName OVNSwitch, aclRules ...OVNACLRule) error { - // Remove any existing rules assigned to the entity. - args := []string{"clear", "logical_switch", string(switchName), "acls"} - - // Add new rules. - externalIDs := map[string]string{ - ovnExtIDIncusSwitch: string(switchName), - } - - args = o.aclRuleAddAppendArgs(args, "logical_switch", string(switchName), externalIDs, nil, aclRules...) - - _, err := o.nbctl(args...) - if err != nil { - return err - } - - return nil -} - -// logicalSwitchPortACLRules returns the ACL rule UUIDs belonging to a logical switch port. -func (o *OVN) logicalSwitchPortACLRules(portName OVNSwitchPort) ([]string, error) { - // Remove any existing rules assigned to the entity. - output, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid", "find", "acl", - fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitchPort, string(portName)), - ) - if err != nil { - return nil, err - } - - ruleUUIDs := util.SplitNTrimSpace(strings.TrimSpace(output), "\n", -1, true) - - return ruleUUIDs, nil -} - -// LogicalSwitchPorts returns a map of logical switch ports (name and UUID) for a switch. -// Includes non-instance ports, such as the router port. -func (o *OVN) LogicalSwitchPorts(switchName OVNSwitch) (map[OVNSwitchPort]OVNSwitchPortUUID, error) { - output, err := o.nbctl("lsp-list", string(switchName)) - if err != nil { - return nil, err - } - - lines := util.SplitNTrimSpace(strings.TrimSpace(output), "\n", -1, true) - ports := make(map[OVNSwitchPort]OVNSwitchPortUUID, len(lines)) - - for _, line := range lines { - // E.g. "c709c4a8-ef3f-4ffe-a45a-c75295eb2698 (incus-net3-instance-fc933d65-0900-46b0-b5f2-4d323342e755-eth0)" - fields := strings.Fields(line) - - if len(fields) != 2 { - return nil, fmt.Errorf("Unrecognised switch port item output %q", line) - } - - portUUID := OVNSwitchPortUUID(fields[0]) - portName := OVNSwitchPort(strings.TrimPrefix(strings.TrimSuffix(fields[1], ")"), "(")) - ports[portName] = portUUID - } - - return ports, nil -} - -// LogicalSwitchIPs returns a list of IPs associated to each port connected to switch. -func (o *OVN) LogicalSwitchIPs(switchName OVNSwitch) (map[OVNSwitchPort][]net.IP, error) { - output, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=name,addresses,dynamic_addresses", "find", "logical_switch_port", - fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName), - ) - if err != nil { - return nil, err - } - - lines := util.SplitNTrimSpace(strings.TrimSpace(output), "\n", -1, true) - portIPs := make(map[OVNSwitchPort][]net.IP, len(lines)) - - for _, line := range lines { - fields := util.SplitNTrimSpace(line, ",", -1, true) - portName := OVNSwitchPort(fields[0]) - var ips []net.IP - - // Parse all IPs mentioned in addresses and dynamic_addresses fields. - for i := 1; i < len(fields); i++ { - for _, address := range util.SplitNTrimSpace(fields[i], " ", -1, true) { - ip := net.ParseIP(address) - if ip != nil { - ips = append(ips, ip) - } - } - } - - portIPs[portName] = ips - } - - return portIPs, nil -} - -// LogicalSwitchPortUUID returns the logical switch port UUID or empty string if port doesn't exist. -func (o *OVN) LogicalSwitchPortUUID(portName OVNSwitchPort) (OVNSwitchPortUUID, error) { - portInfo, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid,name", "find", "logical_switch_port", - fmt.Sprintf("name=%s", string(portName)), - ) - if err != nil { - return "", err - } - - portParts := util.SplitNTrimSpace(portInfo, ",", 2, false) - if len(portParts) == 2 { - if portParts[1] == string(portName) { - return OVNSwitchPortUUID(portParts[0]), nil - } - } - - return "", nil -} - -// LogicalSwitchPortAdd adds a named logical switch port to a logical switch, and sets options if provided. -// If mayExist is true, then an existing resource of the same name is not treated as an error. -func (o *OVN) LogicalSwitchPortAdd(switchName OVNSwitch, portName OVNSwitchPort, opts *OVNSwitchPortOpts, mayExist bool) error { - args := []string{} - - if mayExist { - args = append(args, "--may-exist") - } - - // Add switch port. - args = append(args, "lsp-add", string(switchName), string(portName)) - - // Set switch port options if supplied. - if opts != nil { - // Created nested VLAN port if requested. - if opts.Parent != "" { - args = append(args, string(opts.Parent), fmt.Sprintf("%d", opts.VLAN)) - } - - ipStr := make([]string, 0, len(opts.IPs)) - for _, ip := range opts.IPs { - ipStr = append(ipStr, ip.String()) - } - - var addresses string - if opts.MAC != nil && len(ipStr) > 0 { - addresses = fmt.Sprintf("%s %s", opts.MAC.String(), strings.Join(ipStr, " ")) - } else if opts.MAC != nil && len(ipStr) <= 0 { - addresses = fmt.Sprintf("%s %s", opts.MAC.String(), "dynamic") - } else { - addresses = "dynamic" - } - - args = append(args, "--", "lsp-set-addresses", string(portName), addresses) - - if opts.DHCPv4OptsID != "" { - args = append(args, "--", "lsp-set-dhcpv4-options", string(portName), string(opts.DHCPv4OptsID)) - } - - if opts.DHCPv6OptsID != "" { - args = append(args, "--", "lsp-set-dhcpv6-options", string(portName), string(opts.DHCPv6OptsID)) - } - - if opts.Location != "" { - args = append(args, "--", "set", "logical_switch_port", string(portName), fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusLocation, opts.Location)) - } - } - - args = append(args, "--", "set", "logical_switch_port", string(portName), fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName)) - - _, err := o.nbctl(args...) - if err != nil { - return err - } - - return nil -} - -// LogicalSwitchPortIPs returns a list of IPs for a switch port. -func (o *OVN) LogicalSwitchPortIPs(portName OVNSwitchPort) ([]net.IP, error) { - addressesRaw, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--column=addresses,dynamic_addresses", "find", "logical_switch_port", fmt.Sprintf("name=%s", string(portName))) - if err != nil { - return nil, err - } - - addresses := strings.Split(strings.Replace(strings.TrimSpace(addressesRaw), ",", " ", 1), " ") - ips := make([]net.IP, 0) - - for _, address := range addresses { - ip := net.ParseIP(address) - if ip != nil { - ips = append(ips, ip) - } - } - - return ips, nil -} - -// LogicalSwitchPortDynamicIPs returns a list of dynamc IPs for a switch port. -func (o *OVN) LogicalSwitchPortDynamicIPs(portName OVNSwitchPort) ([]net.IP, error) { - dynamicAddressesRaw, err := o.nbctl("get", "logical_switch_port", string(portName), "dynamic_addresses") - if err != nil { - return nil, err - } - - dynamicAddressesRaw = strings.TrimSpace(dynamicAddressesRaw) - - // Check if no dynamic IPs set. - if dynamicAddressesRaw == "[]" { - return []net.IP{}, nil - } - - dynamicAddressesRaw, err = unquote(dynamicAddressesRaw) - if err != nil { - return nil, fmt.Errorf("Failed unquoting: %w", err) - } - - dynamicAddresses := strings.Split(strings.TrimSpace(dynamicAddressesRaw), " ") - dynamicIPs := make([]net.IP, 0, len(dynamicAddresses)) - - for _, dynamicAddress := range dynamicAddresses { - ip := net.ParseIP(dynamicAddress) - if ip != nil { - dynamicIPs = append(dynamicIPs, ip) - } - } - - return dynamicIPs, nil -} - -// LogicalSwitchPortLocationGet returns the last set location of a logical switch port. -func (o *OVN) LogicalSwitchPortLocationGet(portName OVNSwitchPort) (string, error) { - location, err := o.nbctl("--if-exists", "get", "logical_switch_port", string(portName), fmt.Sprintf("external-ids:%s", ovnExtIDIncusLocation)) - if err != nil { - return "", err - } - - return strings.TrimSpace(location), nil -} - -// LogicalSwitchPortOptionsSet sets the options for a logical switch port. -func (o *OVN) LogicalSwitchPortOptionsSet(portName OVNSwitchPort, options map[string]string) error { - args := []string{"lsp-set-options", string(portName)} - - for key, value := range options { - args = append(args, fmt.Sprintf("%s=%s", key, value)) - } - - _, err := o.nbctl(args...) - if err != nil { - return err - } - - return nil -} - -// LogicalSwitchPortSetDNS sets up the switch port DNS records for the DNS name. -// Returns the DNS record UUID, IPv4 and IPv6 addresses used for DNS records. -func (o *OVN) LogicalSwitchPortSetDNS(switchName OVNSwitch, portName OVNSwitchPort, dnsName string, dnsIPs []net.IP) (OVNDNSUUID, error) { - // Check if existing DNS record exists for switch port. - dnsUUID, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid", "find", "dns", - fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitchPort, portName), - ) - if err != nil { - return "", err - } - - cmdArgs := []string{ - fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName), - fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitchPort, portName), - } - - // Only include DNS name record if IPs supplied. - if len(dnsIPs) > 0 { - var dnsIPsStr strings.Builder - for i, dnsIP := range dnsIPs { - if i > 0 { - dnsIPsStr.WriteString(" ") - } - - dnsIPsStr.WriteString(dnsIP.String()) - } - - cmdArgs = append(cmdArgs, fmt.Sprintf(`records={"%s"="%s"}`, strings.ToLower(dnsName), dnsIPsStr.String())) - } - - dnsUUID = strings.TrimSpace(dnsUUID) - if dnsUUID != "" { - // Clear any existing DNS name if no IPs supplied. - if len(dnsIPs) < 1 { - cmdArgs = append(cmdArgs, "--", "clear", "dns", string(dnsUUID), "records") - } - - // Update existing record if exists. - _, err = o.nbctl(append([]string{"set", "dns", dnsUUID}, cmdArgs...)...) - if err != nil { - return "", err - } - } else { - // Create new record if needed. - dnsUUID, err = o.nbctl(append([]string{"create", "dns"}, cmdArgs...)...) - if err != nil { - return "", err - } - - dnsUUID = strings.TrimSpace(dnsUUID) - } - - // Add DNS record to switch DNS records. - _, err = o.nbctl("add", "logical_switch", string(switchName), "dns_records", dnsUUID) - if err != nil { - return "", err - } - - return OVNDNSUUID(dnsUUID), nil -} - -// LogicalSwitchPortGetDNS returns the logical switch port DNS info (UUID, name and IPs). -func (o *OVN) LogicalSwitchPortGetDNS(portName OVNSwitchPort) (OVNDNSUUID, string, []net.IP, error) { - // Get UUID and DNS IPs for a switch port in the format: ",= " - output, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid,records", "find", "dns", - fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitchPort, portName), - ) - if err != nil { - return "", "", nil, err - } - - parts := strings.Split(strings.TrimSpace(output), ",") - dnsUUID := strings.TrimSpace(parts[0]) - - var dnsName string - var ips []net.IP - - // Try and parse the DNS name and IPs. - if len(parts) > 1 { - dnsParts := strings.SplitN(strings.TrimSpace(parts[1]), "=", 2) - if len(dnsParts) == 2 { - dnsName = strings.TrimSpace(dnsParts[0]) - ipParts := strings.Split(dnsParts[1], " ") - for _, ipPart := range ipParts { - ip := net.ParseIP(strings.TrimSpace(ipPart)) - if ip != nil { - ips = append(ips, ip) - } - } - } - } - - return OVNDNSUUID(dnsUUID), dnsName, ips, nil -} - -// logicalSwitchPortDeleteDNSAppendArgs adds the command arguments to remove DNS records from a switch port. -// If destroyEntry the DNS entry record itself is also removed, otherwise it is just cleared but left in place. -// Returns args with the commands added to it. -func (o *OVN) logicalSwitchPortDeleteDNSAppendArgs(args []string, switchName OVNSwitch, dnsUUID OVNDNSUUID, destroyEntry bool) []string { - if len(args) > 0 { - args = append(args, "--") - } - - args = append(args, "remove", "logical_switch", string(switchName), "dns_records", string(dnsUUID), "--") - - if destroyEntry { - args = append(args, "destroy", "dns", string(dnsUUID)) - } else { - args = append(args, "clear", "dns", string(dnsUUID), "records") - } - - return args -} - -// LogicalSwitchPortDeleteDNS removes DNS records from a switch port. -// If destroyEntry the DNS entry record itself is also removed, otherwise it is just cleared but left in place. -func (o *OVN) LogicalSwitchPortDeleteDNS(switchName OVNSwitch, dnsUUID OVNDNSUUID, destroyEntry bool) error { - // Remove DNS record association from switch, and remove DNS record entry itself. - _, err := o.nbctl(o.logicalSwitchPortDeleteDNSAppendArgs(nil, switchName, dnsUUID, destroyEntry)...) - if err != nil { - return err - } - - return nil -} - -// logicalSwitchPortDeleteAppendArgs adds the commands to delete the specified logical switch port. -// Returns args with the commands added to it. -func (o *OVN) logicalSwitchPortDeleteAppendArgs(args []string, portName OVNSwitchPort) []string { - if len(args) > 0 { - args = append(args, "--") - } - - args = append(args, "--if-exists", "lsp-del", string(portName)) - - return args -} - -// LogicalSwitchPortDelete deletes a named logical switch port. -func (o *OVN) LogicalSwitchPortDelete(portName OVNSwitchPort) error { - _, err := o.nbctl(o.logicalSwitchPortDeleteAppendArgs(nil, portName)...) - if err != nil { - return err - } - - return nil -} - -// LogicalSwitchPortCleanup deletes the named logical switch port and its associated config. -func (o *OVN) LogicalSwitchPortCleanup(portName OVNSwitchPort, switchName OVNSwitch, switchPortGroupName OVNPortGroup, dnsUUID OVNDNSUUID) error { - // Remove any existing rules assigned to the entity. - removeACLRuleUUIDs, err := o.logicalSwitchPortACLRules(portName) - if err != nil { - return err - } - - args := o.aclRuleDeleteAppendArgs(nil, "port_group", string(switchPortGroupName), removeACLRuleUUIDs) - - // Remove logical switch port. - args = o.logicalSwitchPortDeleteAppendArgs(args, portName) - - // Remove DNS records. - if dnsUUID != "" { - args = o.logicalSwitchPortDeleteDNSAppendArgs(args, switchName, dnsUUID, false) - } - - _, err = o.nbctl(args...) - if err != nil { - return err - } - - return nil -} - -// LogicalSwitchPortLinkRouter links a logical switch port to a logical router port. -func (o *OVN) LogicalSwitchPortLinkRouter(switchPortName OVNSwitchPort, routerPortName OVNRouterPort) error { - // Connect logical router port to switch. - _, err := o.nbctl( - "lsp-set-type", string(switchPortName), "router", "--", - "lsp-set-addresses", string(switchPortName), "router", "--", - "lsp-set-options", string(switchPortName), fmt.Sprintf("nat-addresses=%s", "router"), fmt.Sprintf("router-port=%s", string(routerPortName)), - ) - if err != nil { - return err - } - - return nil -} - -// LogicalSwitchPortLinkProviderNetwork links a logical switch port to a provider network. -func (o *OVN) LogicalSwitchPortLinkProviderNetwork(switchPortName OVNSwitchPort, extNetworkName string) error { - // Forward any unknown MAC frames down this port. - _, err := o.nbctl( - "lsp-set-addresses", string(switchPortName), "unknown", "--", - "lsp-set-type", string(switchPortName), "localnet", "--", - "lsp-set-options", string(switchPortName), fmt.Sprintf("network_name=%s", extNetworkName), - ) - if err != nil { - return err - } - - return nil -} - -// ChassisGroupAdd adds a new HA chassis group. -// If mayExist is true, then an existing resource of the same name is not treated as an error. -func (o *OVN) ChassisGroupAdd(haChassisGroupName OVNChassisGroup, mayExist bool) error { - if mayExist { - // Check if it exists (sadly ha-chassis-group-add doesn't provide --may-exist option). - _, err := o.nbctl("list", "HA_Chassis_Group", string(haChassisGroupName)) - if err == nil { - return nil // Chassis group exists. - } - } - - _, err := o.nbctl("ha-chassis-group-add", string(haChassisGroupName)) - if err != nil { - return err - } - - return nil -} - -// ChassisGroupDelete deletes an HA chassis group. -func (o *OVN) ChassisGroupDelete(haChassisGroupName OVNChassisGroup) error { - // ovn-nbctl doesn't provide an "--if-exists" option for removing chassis groups. - existing, err := o.nbctl("--no-headings", "--data=bare", "--colum=name", "find", "ha_chassis_group", fmt.Sprintf("name=%s", string(haChassisGroupName))) - if err != nil { - return err - } - - // Remove chassis group if exists. - if strings.TrimSpace(existing) != "" { - _, err := o.nbctl("ha-chassis-group-del", string(haChassisGroupName)) - if err != nil { - return err - } - } - - return nil -} - -// ChassisGroupChassisAdd adds a chassis ID to an HA chassis group with the specified priority. -func (o *OVN) ChassisGroupChassisAdd(haChassisGroupName OVNChassisGroup, chassisID string, priority uint) error { - _, err := o.nbctl("ha-chassis-group-add-chassis", string(haChassisGroupName), chassisID, fmt.Sprintf("%d", priority)) - if err != nil { - return err - } - - return nil -} - -// ChassisGroupChassisDelete deletes a chassis ID from an HA chassis group. -func (o *OVN) ChassisGroupChassisDelete(haChassisGroupName OVNChassisGroup, chassisID string) error { - // Check if chassis group exists. ovn-nbctl doesn't provide an "--if-exists" option for this. - output, err := o.nbctl("--no-headings", "--data=bare", "--colum=name,ha_chassis", "find", "ha_chassis_group", fmt.Sprintf("name=%s", string(haChassisGroupName))) - if err != nil { - return err - } - - lines := util.SplitNTrimSpace(output, "\n", -1, true) - if len(lines) > 1 { - existingChassisGroup := lines[0] - members := util.SplitNTrimSpace(lines[1], " ", -1, true) - - // Remove chassis from group if exists. - if existingChassisGroup == string(haChassisGroupName) && util.ValueInSlice(chassisID, members) { - _, err := o.nbctl("ha-chassis-group-remove-chassis", string(haChassisGroupName), chassisID) - if err != nil { - return err - } - } - } - - // Nothing to do if chassis group doesn't exist. - return nil -} - -// PortGroupInfo returns the port group UUID or empty string if port doesn't exist, and whether the port group has -// any ACL rules defined on it. -func (o *OVN) PortGroupInfo(portGroupName OVNPortGroup) (OVNPortGroupUUID, bool, error) { - groupInfo, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid,name,acl", "find", "port_group", - fmt.Sprintf("name=%s", string(portGroupName)), - ) - if err != nil { - return "", false, err - } - - groupParts := util.SplitNTrimSpace(groupInfo, ",", 3, true) - if len(groupParts) == 3 { - if groupParts[1] == string(portGroupName) { - aclParts := util.SplitNTrimSpace(groupParts[2], ",", -1, true) - - return OVNPortGroupUUID(groupParts[0]), len(aclParts) > 0, nil - } - } - - return "", false, nil -} - -// PortGroupAdd creates a new port group and optionally adds logical switch ports to the group. -func (o *OVN) PortGroupAdd(projectID int64, portGroupName OVNPortGroup, associatedPortGroup OVNPortGroup, associatedSwitch OVNSwitch, initialPortMembers ...OVNSwitchPort) error { - args := []string{"pg-add", string(portGroupName)} - for _, portName := range initialPortMembers { - args = append(args, string(portName)) - } - - args = append(args, "--", "set", "port_group", string(portGroupName), - fmt.Sprintf("external_ids:%s=%d", ovnExtIDIncusProjectID, projectID), - ) - - if associatedPortGroup != "" || associatedSwitch != "" { - if associatedPortGroup != "" { - args = append(args, fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusPortGroup, associatedPortGroup)) - } - - if associatedSwitch != "" { - args = append(args, fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, associatedSwitch)) - } - } - - _, err := o.nbctl(args...) - if err != nil { - return err - } - - return nil -} - -// PortGroupDelete deletes port groups along with their ACL rules. -func (o *OVN) PortGroupDelete(portGroupNames ...OVNPortGroup) error { - args := make([]string, 0) - - for _, portGroupName := range portGroupNames { - if len(args) > 0 { - args = append(args, "--") - } - - args = append(args, "--if-exists", "destroy", "port_group", string(portGroupName)) - } - - _, err := o.nbctl(args...) - if err != nil { - return err - } - - return nil -} - -// PortGroupListByProject finds the port groups that are associated to the project ID. -func (o *OVN) PortGroupListByProject(projectID int64) ([]OVNPortGroup, error) { - output, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=name", "find", "port_group", - fmt.Sprintf("external_ids:%s=%d", ovnExtIDIncusProjectID, projectID), - ) - if err != nil { - return nil, err - } - - lines := util.SplitNTrimSpace(strings.TrimSpace(output), "\n", -1, true) - portGroups := make([]OVNPortGroup, 0, len(lines)) - - for _, line := range lines { - portGroups = append(portGroups, OVNPortGroup(line)) - } - - return portGroups, nil -} - -// PortGroupMemberChange adds/removes logical switch ports (by UUID) to/from existing port groups. -func (o *OVN) PortGroupMemberChange(addMembers map[OVNPortGroup][]OVNSwitchPortUUID, removeMembers map[OVNPortGroup][]OVNSwitchPortUUID) error { - args := []string{} - - for portGroupName, portMemberUUIDs := range addMembers { - for _, portMemberUUID := range portMemberUUIDs { - if len(args) > 0 { - args = append(args, "--") - } - - args = append(args, "add", "port_group", string(portGroupName), "ports", string(portMemberUUID)) - } - } - - for portGroupName, portMemberUUIDs := range removeMembers { - for _, portMemberUUID := range portMemberUUIDs { - if len(args) > 0 { - args = append(args, "--") - } - - args = append(args, "--if-exists", "remove", "port_group", string(portGroupName), "ports", string(portMemberUUID)) - } - } - - _, err := o.nbctl(args...) - if err != nil { - return err - } - - return nil -} - -// PortGroupSetACLRules applies a set of rules to the specified port group. Any existing rules are removed. -func (o *OVN) PortGroupSetACLRules(portGroupName OVNPortGroup, matchReplace map[string]string, aclRules ...OVNACLRule) error { - // Remove any existing rules assigned to the entity. - args := []string{"clear", "port_group", string(portGroupName), "acls"} - - // Add new rules. - externalIDs := map[string]string{ - ovnExtIDIncusPortGroup: string(portGroupName), - } - - args = o.aclRuleAddAppendArgs(args, "port_group", string(portGroupName), externalIDs, matchReplace, aclRules...) - - _, err := o.nbctl(args...) - if err != nil { - return err - } - - return nil -} - -// aclRuleAddAppendArgs adds the commands to args that add the provided ACL rules to the specified OVN entity. -// Returns args with the ACL rule add commands added to it. -func (o *OVN) aclRuleAddAppendArgs(args []string, entityTable string, entityName string, externalIDs map[string]string, matchReplace map[string]string, aclRules ...OVNACLRule) []string { - for i, rule := range aclRules { - if len(args) > 0 { - args = append(args, "--") - } - - // Perform any replacements requested on the Match string. - for find, replace := range matchReplace { - rule.Match = strings.ReplaceAll(rule.Match, find, replace) - } - - // Add command to create ACL rule. - args = append(args, fmt.Sprintf("--id=@id%d", i), "create", "acl", - fmt.Sprintf("action=%s", rule.Action), - fmt.Sprintf("direction=%s", rule.Direction), - fmt.Sprintf("priority=%d", rule.Priority), - fmt.Sprintf("match=%s", strconv.Quote(rule.Match)), - ) - - if rule.Log { - args = append(args, "log=true") - - if rule.LogName != "" { - args = append(args, fmt.Sprintf("name=%s", rule.LogName)) - } - } - - for k, v := range externalIDs { - args = append(args, fmt.Sprintf("external_ids:%s=%s", k, v)) - } - - // Add command to assign ACL rule to entity. - args = append(args, "--", "add", entityTable, entityName, "acl", fmt.Sprintf("@id%d", i)) - } - - return args -} - -// aclRuleDeleteAppendArgs adds the commands to args that delete the provided ACL rules from the specified OVN entity. -// Returns args with the ACL rule delete commands added to it. -func (o *OVN) aclRuleDeleteAppendArgs(args []string, entityTable string, entityName string, aclRuleUUIDs []string) []string { - for _, aclRuleUUID := range aclRuleUUIDs { - if len(args) > 0 { - args = append(args, "--") - } - - args = append(args, "remove", entityTable, string(entityName), "acl", aclRuleUUID) - } - - return args -} - -// PortGroupPortSetACLRules applies a set of rules for the logical switch port in the specified port group. -// Any existing rules for that logical switch port in the port group are removed. -func (o *OVN) PortGroupPortSetACLRules(portGroupName OVNPortGroup, portName OVNSwitchPort, aclRules ...OVNACLRule) error { - // Remove any existing rules assigned to the entity. - removeACLRuleUUIDs, err := o.logicalSwitchPortACLRules(portName) - if err != nil { - return err - } - - args := o.aclRuleDeleteAppendArgs(nil, "port_group", string(portGroupName), removeACLRuleUUIDs) - - // Add new rules. - externalIDs := map[string]string{ - ovnExtIDIncusPortGroup: string(portGroupName), - ovnExtIDIncusSwitchPort: string(portName), - } - - args = o.aclRuleAddAppendArgs(args, "port_group", string(portGroupName), externalIDs, nil, aclRules...) - - _, err = o.nbctl(args...) - if err != nil { - return err - } - - return nil -} - -// PortGroupPortClearACLRules clears any rules assigned to the logical switch port in the specified port group. -func (o *OVN) PortGroupPortClearACLRules(portGroupName OVNPortGroup, portName OVNSwitchPort) error { - // Remove any existing rules assigned to the entity. - removeACLRuleUUIDs, err := o.logicalSwitchPortACLRules(portName) - if err != nil { - return err - } - - args := o.aclRuleDeleteAppendArgs(nil, "port_group", string(portGroupName), removeACLRuleUUIDs) - - if len(args) > 0 { - _, err = o.nbctl(args...) - if err != nil { - return err - } - } - - return nil -} - -// LoadBalancerApply creates a new load balancer (if doesn't exist) on the specified routers and switches. -// Providing an empty set of vips will delete the load balancer. -func (o *OVN) LoadBalancerApply(loadBalancerName OVNLoadBalancer, routers []OVNRouter, switches []OVNSwitch, vips ...OVNLoadBalancerVIP) error { - lbTCPName := fmt.Sprintf("%s-tcp", loadBalancerName) - lbUDPName := fmt.Sprintf("%s-udp", loadBalancerName) - - // Remove existing load balancers if they exist. - args := []string{"--if-exists", "lb-del", lbTCPName, "--", "lb-del", lbUDPName} - - // ipToString wraps IPv6 addresses in square brackets. - ipToString := func(ip net.IP) string { - if ip.To4() == nil { - return fmt.Sprintf("[%s]", ip.String()) - } - - return ip.String() - } - - // We have to use a separate load balancer for UDP rules so use this to keep track of whether we need it. - lbNames := make(map[string]struct{}) - - // Build up the commands to add VIPs to the load balancer. - for _, r := range vips { - if r.ListenAddress == nil { - return fmt.Errorf("Missing VIP listen address") - } - - if len(r.Targets) == 0 { - return fmt.Errorf("Missing VIP target(s)") - } - - if r.Protocol == "udp" { - args = append(args, "--", "lb-add", lbUDPName) - lbNames[lbUDPName] = struct{}{} // Record that UDP load balancer is created. - } else { - args = append(args, "--", "lb-add", lbTCPName) - lbNames[lbTCPName] = struct{}{} // Record that TCP load balancer is created. - } - - targetArgs := make([]string, 0, len(r.Targets)) - - for _, target := range r.Targets { - if (r.ListenPort > 0 && target.Port <= 0) || (target.Port > 0 && r.ListenPort <= 0) { - return fmt.Errorf("The listen and target ports must be specified together") - } - - if r.ListenPort > 0 { - targetArgs = append(targetArgs, fmt.Sprintf("%s:%d", ipToString(target.Address), target.Port)) - } else { - targetArgs = append(targetArgs, ipToString(target.Address)) - } - } - - if r.ListenPort > 0 { - args = append(args, - fmt.Sprintf("%s:%d", ipToString(r.ListenAddress), r.ListenPort), - strings.Join(targetArgs, ","), - r.Protocol, - ) - } else { - args = append(args, - ipToString(r.ListenAddress), - strings.Join(targetArgs, ","), - ) - } - } - - // If there are some VIP rules then associate the load balancer to the requested routers and switches. - if len(vips) > 0 { - for _, r := range routers { - _, found := lbNames[lbTCPName] - if found { - args = append(args, "--", "lr-lb-add", string(r), lbTCPName) - } - - _, found = lbNames[lbUDPName] - if found { - args = append(args, "--", "lr-lb-add", string(r), lbUDPName) - } - } - - for _, s := range switches { - _, found := lbNames[lbTCPName] - if found { - args = append(args, "--", "ls-lb-add", string(s), lbTCPName) - } - - _, found = lbNames[lbUDPName] - if found { - args = append(args, "--", "ls-lb-add", string(s), lbUDPName) - } - } - } - - _, err := o.nbctl(args...) - if err != nil { - return err - } - - return nil -} - -// LoadBalancerDelete deletes the specified load balancer(s). -func (o *OVN) LoadBalancerDelete(loadBalancerNames ...OVNLoadBalancer) error { - var args []string - - for _, loadBalancerName := range loadBalancerNames { - if len(args) > 0 { - args = append(args, "--") - } - - lbTCPName := fmt.Sprintf("%s-tcp", loadBalancerName) - lbUDPName := fmt.Sprintf("%s-udp", loadBalancerName) - - // Remove load balancers for loadBalancerName if they exist. - args = append(args, "--if-exists", "lb-del", lbTCPName, "--", "lb-del", lbUDPName) - } - - if len(args) > 0 { - _, err := o.nbctl(args...) - if err != nil { - return err - } - } - - return nil -} - -// AddressSetCreate creates address sets for IP versions 4 and 6 in the format "_ip". -// Populates them with the relevant addresses supplied. -func (o *OVN) AddressSetCreate(addressSetPrefix OVNAddressSet, addresses ...net.IPNet) error { - args := []string{ - "create", "address_set", fmt.Sprintf("name=%s_ip%d", addressSetPrefix, 4), - "--", "create", "address_set", fmt.Sprintf("name=%s_ip%d", addressSetPrefix, 6), - } - - for _, address := range addresses { - if len(args) > 0 { - args = append(args, "--") - } - - var ipVersion uint = 4 - if address.IP.To4() == nil { - ipVersion = 6 - } - - args = append(args, "add", "address_set", fmt.Sprintf("%s_ip%d", addressSetPrefix, ipVersion), "addresses", fmt.Sprintf(`"%s"`, address.String())) - } - - if len(args) > 0 { - _, err := o.nbctl(args...) - if err != nil { - return err - } - } - - return nil -} - -// AddressSetAdd adds the supplied addresses to the address sets, or creates a new address sets if needed. -// The address set name used is "_ip", e.g. "foo_ip4". -func (o *OVN) AddressSetAdd(addressSetPrefix OVNAddressSet, addresses ...net.IPNet) error { - var args []string - ipVersions := make(map[uint]struct{}) - - for _, address := range addresses { - if len(args) > 0 { - args = append(args, "--") - } - - var ipVersion uint = 4 - if address.IP.To4() == nil { - ipVersion = 6 - } - - // Track IP versions seen so we can create address sets if needed. - ipVersions[ipVersion] = struct{}{} - - args = append(args, "add", "address_set", fmt.Sprintf("%s_ip%d", addressSetPrefix, ipVersion), "addresses", fmt.Sprintf(`"%s"`, address.String())) - } - - if len(args) > 0 { - // Optimistically assume all required address sets exist (they normally will). - _, err := o.nbctl(args...) - if err != nil { - // Try creating the address sets one at a time, but ignore errors here in case some of the - // address sets already exist. If there was a problem creating the address set it will be - // revealead when we run the original command again next. - for ipVersion := range ipVersions { - _, _ = o.nbctl("create", "address_set", fmt.Sprintf("name=%s_ip%d", addressSetPrefix, ipVersion)) - } - - // Try original command again. - _, err := o.nbctl(args...) - if err != nil { - return err - } - } - } - - return nil -} - -// AddressSetRemove removes the supplied addresses from the address set. -// The address set name used is "_ip", e.g. "foo_ip4". -func (o *OVN) AddressSetRemove(addressSetPrefix OVNAddressSet, addresses ...net.IPNet) error { - var args []string - - for _, address := range addresses { - if len(args) > 0 { - args = append(args, "--") - } - - var ipVersion uint = 4 - if address.IP.To4() == nil { - ipVersion = 6 - } - - args = append(args, "--if-exists", "remove", "address_set", fmt.Sprintf("%s_ip%d", addressSetPrefix, ipVersion), "addresses", fmt.Sprintf(`"%s"`, address.String())) - } - - if len(args) > 0 { - _, err := o.nbctl(args...) - if err != nil { - return err - } - } - - return nil -} - -// AddressSetDelete deletes address sets for IP versions 4 and 6 in the format "_ip". -func (o *OVN) AddressSetDelete(addressSetPrefix OVNAddressSet) error { - _, err := o.nbctl( - "--if-exists", "destroy", "address_set", fmt.Sprintf("%s_ip%d", addressSetPrefix, 4), - "--", "--if-exists", "destroy", "address_set", fmt.Sprintf("%s_ip%d", addressSetPrefix, 6), - ) - if err != nil { - return err - } - - return nil -} - -// LogicalRouterPolicyApply removes any existing policies and applies the new policies to the specified router. -func (o *OVN) LogicalRouterPolicyApply(routerName OVNRouter, policies ...OVNRouterPolicy) error { - args := []string{"lr-policy-del", string(routerName)} - - for _, policy := range policies { - args = append(args, "--", "lr-policy-add", string(routerName), fmt.Sprintf("%d", policy.Priority), policy.Match, policy.Action) - } - - _, err := o.nbctl(args...) - if err != nil { - return err - } - - return nil -} - -// LogicalRouterRoutes returns a list of static routes in the main route table of the logical router. -func (o *OVN) LogicalRouterRoutes(routerName OVNRouter) ([]OVNRouterRoute, error) { - output, err := o.nbctl("lr-route-list", string(routerName)) - if err != nil { - return nil, err - } - - lines := util.SplitNTrimSpace(strings.TrimSpace(output), "\n", -1, true) - routes := make([]OVNRouterRoute, 0) - - mainTable := true // Assume output starts with main table (supports ovn versions without multiple tables). - for i, line := range lines { - if line == "IPv4 Routes" || line == "IPv6 Routes" { - continue // Ignore heading category lines. - } - - // Keep track of which route table we are looking at. - if strings.HasPrefix(line, "Route Table") { - if line == "Route Table
:" { - mainTable = true - } else { - mainTable = false - } - - continue - } - - if !mainTable { - continue // We don't currently consider routes in other route tables. - } - - // E.g. "10.97.31.0/24 10.97.31.1 dst-ip [optional-some-router-port-name]" - fields := strings.Fields(line) - fieldsLen := len(fields) - - if fieldsLen <= 0 { - continue // Ignore empty lines. - } else if fieldsLen < 3 || fieldsLen > 4 { - return nil, fmt.Errorf("Unrecognised static route item output on line %d: %q", i, line) - } - - var route OVNRouterRoute - - // ovn-nbctl doesn't output single-host route prefixes in CIDR format, so do the conversion here. - ip := net.ParseIP(fields[0]) - if ip != nil { - subnetSize := 32 - if ip.To4() == nil { - subnetSize = 128 - } - - fields[0] = fmt.Sprintf("%s/%d", ip.String(), subnetSize) - } - - _, prefix, err := net.ParseCIDR(fields[0]) - if err != nil { - return nil, fmt.Errorf("Invalid static route prefix on line %d: %q", i, fields[0]) - } - - route.Prefix = *prefix - route.NextHop = net.ParseIP(fields[1]) - - if fieldsLen > 3 { - route.Port = OVNRouterPort(fields[3]) - } - - routes = append(routes, route) - } - - return routes, nil -} - -// LogicalRouterPeeringApply applies a peering relationship between two logical routers. -func (o *OVN) LogicalRouterPeeringApply(opts OVNRouterPeering) error { - if len(opts.LocalRouterPortIPs) <= 0 || len(opts.TargetRouterPortIPs) <= 0 { - return fmt.Errorf("IPs not populated for both router ports") - } - - // Remove peering router ports and static routes using ports from both routers. - // Run the delete step as a separate command to workaround a bug in OVN. - err := o.LogicalRouterPeeringDelete(opts) - if err != nil { - return err - } - - // Start fresh command set. - var args []string - - // Will use the first IP from each family of the router port interfaces. - localRouterGatewayIPs := make(map[uint]net.IP, 0) - targetRouterGatewayIPs := make(map[uint]net.IP, 0) - - // Setup local router port peered with target router port. - args = append(args, "--", "lrp-add", string(opts.LocalRouter), string(opts.LocalRouterPort), opts.LocalRouterPortMAC.String()) - for _, ipNet := range opts.LocalRouterPortIPs { - ipVersion := uint(4) - if ipNet.IP.To4() == nil { - ipVersion = 6 - } - - if localRouterGatewayIPs[ipVersion] == nil { - localRouterGatewayIPs[ipVersion] = ipNet.IP - } - - args = append(args, ipNet.String()) - } - - args = append(args, fmt.Sprintf("peer=%s", opts.TargetRouterPort)) - - // Setup target router port peered with local router port. - args = append(args, "--", "lrp-add", string(opts.TargetRouter), string(opts.TargetRouterPort), opts.TargetRouterPortMAC.String()) - for _, ipNet := range opts.TargetRouterPortIPs { - ipVersion := uint(4) - if ipNet.IP.To4() == nil { - ipVersion = 6 - } - - if targetRouterGatewayIPs[ipVersion] == nil { - targetRouterGatewayIPs[ipVersion] = ipNet.IP - } - - args = append(args, ipNet.String()) - } - - args = append(args, fmt.Sprintf("peer=%s", opts.LocalRouterPort)) - - // Add routes using the first router gateway IP for each family for next hop address. - for _, route := range opts.LocalRouterRoutes { - ipVersion := uint(4) - if route.IP.To4() == nil { - ipVersion = 6 - } - - nextHopIP := targetRouterGatewayIPs[ipVersion] - - if nextHopIP == nil { - return fmt.Errorf("Missing target router port IPv%d address for local route %q nexthop address", ipVersion, route.String()) - } - - args = append(args, "--", "--may-exist", "lr-route-add", string(opts.LocalRouter), route.String(), nextHopIP.String(), string(opts.LocalRouterPort)) - } - - for _, route := range opts.TargetRouterRoutes { - ipVersion := uint(4) - if route.IP.To4() == nil { - ipVersion = 6 - } - - nextHopIP := localRouterGatewayIPs[ipVersion] - - if nextHopIP == nil { - return fmt.Errorf("Missing local router port IPv%d address for target route %q nexthop address", ipVersion, route.String()) - } - - args = append(args, "--", "--may-exist", "lr-route-add", string(opts.TargetRouter), route.String(), nextHopIP.String(), string(opts.TargetRouterPort)) - } - - if len(args) > 0 { - _, err := o.nbctl(args...) - if err != nil { - return err - } - } - - return nil -} - -// LogicalRouterPeeringDelete deletes a peering relationship between two logical routers. -// Requires LocalRouter, LocalRouterPort, TargetRouter and TargetRouterPort opts fields to be populated. -func (o *OVN) LogicalRouterPeeringDelete(opts OVNRouterPeering) error { - // Remove peering router ports and static routes using ports from both routers. - if opts.LocalRouter == "" || opts.TargetRouter == "" { - return fmt.Errorf("Router names not populated for both routers") - } - - args := []string{ - "--if-exists", "lrp-del", string(opts.LocalRouterPort), "--", - "--if-exists", "lrp-del", string(opts.TargetRouterPort), - } - - // Remove static routes from both routers that use the respective peering router ports. - staticRoutes, err := o.LogicalRouterRoutes(opts.LocalRouter) - if err != nil { - return fmt.Errorf("Failed getting static routes for local peer router %q: %w", opts.LocalRouter, err) - } - - for _, staticRoute := range staticRoutes { - if staticRoute.Port == opts.LocalRouterPort { - args = append(args, "--", "lr-route-del", string(opts.LocalRouter), staticRoute.Prefix.String(), staticRoute.NextHop.String(), string(opts.LocalRouterPort)) - } - } - - staticRoutes, err = o.LogicalRouterRoutes(opts.TargetRouter) - if err != nil { - return fmt.Errorf("Failed getting static routes for target peer router %q: %w", opts.TargetRouter, err) - } - - for _, staticRoute := range staticRoutes { - if staticRoute.Port == opts.TargetRouterPort { - args = append(args, "--", "lr-route-del", string(opts.TargetRouter), staticRoute.Prefix.String(), staticRoute.NextHop.String(), string(opts.TargetRouterPort)) - } - } - - if len(args) > 0 { - _, err := o.nbctl(args...) - if err != nil { - return err - } - } - - return nil -} - -// GetHardwareAddress gets the hardware address of the logical router port. -func (o *OVN) GetHardwareAddress(ovnRouterPort OVNRouterPort) (string, error) { - nameFilter := fmt.Sprintf("name=%s", ovnRouterPort) - hwaddr, err := o.nbctl("--no-headings", "--data=bare", "--format=csv", "--columns=mac", "find", "Logical_Router_Port", nameFilter) - if err != nil { - return "", err - } - - return strings.TrimSpace(hwaddr), nil -} - -// GetLogicalRouterPortActiveChassisHostname gets the hostname of the chassis managing the logical router port. -func (o *OVN) GetLogicalRouterPortActiveChassisHostname(ovnRouterPort OVNRouterPort) (string, error) { - // Get the chassis ID from port bindings where the logical port is a chassis redirect (prepended "cr-") of the logical router port name. - filter := fmt.Sprintf("logical_port=cr-%s", ovnRouterPort) - chassisID, err := o.sbctl("--no-headings", "--columns=chassis", "--data=bare", "--format=csv", "find", "Port_Binding", filter) - if err != nil { - return "", err - } - - hostname, err := o.sbctl("get", "Chassis", strings.TrimSpace(chassisID), "hostname") - if err != nil { - return "", err - } - - return strings.TrimSpace(hostname), err -} diff --git a/internal/server/network/openvswitch/ovn_actions.go b/internal/server/network/openvswitch/ovn_actions.go new file mode 100644 index 00000000000..aa785738299 --- /dev/null +++ b/internal/server/network/openvswitch/ovn_actions.go @@ -0,0 +1,2208 @@ +package openvswitch + +import ( + "fmt" + "net" + "strconv" + "strings" + "time" + + "github.com/lxc/incus/internal/iprange" + "github.com/lxc/incus/shared/util" +) + +// OVNRouter OVN router name. +type OVNRouter string + +// OVNRouterPort OVN router port name. +type OVNRouterPort string + +// OVNSwitch OVN switch name. +type OVNSwitch string + +// OVNSwitchPort OVN switch port name. +type OVNSwitchPort string + +// OVNSwitchPortUUID OVN switch port UUID. +type OVNSwitchPortUUID string + +// OVNChassisGroup OVN HA chassis group name. +type OVNChassisGroup string + +// OVNDNSUUID OVN DNS record UUID. +type OVNDNSUUID string + +// OVNDHCPOptionsUUID DHCP Options set UUID. +type OVNDHCPOptionsUUID string + +// OVNPortGroup OVN port group name. +type OVNPortGroup string + +// OVNPortGroupUUID OVN port group UUID. +type OVNPortGroupUUID string + +// OVNLoadBalancer OVN load balancer name. +type OVNLoadBalancer string + +// OVNAddressSet OVN address set for ACLs. +type OVNAddressSet string + +// OVNIPAllocationOpts defines IP allocation settings that can be applied to a logical switch. +type OVNIPAllocationOpts struct { + PrefixIPv4 *net.IPNet + PrefixIPv6 *net.IPNet + ExcludeIPv4 []iprange.Range +} + +// OVNIPv6AddressMode IPv6 router advertisement address mode. +type OVNIPv6AddressMode string + +// OVNIPv6AddressModeSLAAC IPv6 SLAAC mode. +const OVNIPv6AddressModeSLAAC OVNIPv6AddressMode = "slaac" + +// OVNIPv6AddressModeDHCPStateful IPv6 DHCPv6 stateful mode. +const OVNIPv6AddressModeDHCPStateful OVNIPv6AddressMode = "dhcpv6_stateful" + +// OVNIPv6AddressModeDHCPStateless IPv6 DHCPv6 stateless mode. +const OVNIPv6AddressModeDHCPStateless OVNIPv6AddressMode = "dhcpv6_stateless" + +// OVN External ID names used by Incus. +const ovnExtIDIncusSwitch = "incus_switch" +const ovnExtIDIncusSwitchPort = "incus_switch_port" +const ovnExtIDIncusProjectID = "incus_project_id" +const ovnExtIDIncusPortGroup = "incus_port_group" +const ovnExtIDIncusLocation = "incus_location" + +// OVNIPv6RAOpts IPv6 router advertisements options that can be applied to a router. +type OVNIPv6RAOpts struct { + SendPeriodic bool + AddressMode OVNIPv6AddressMode + MinInterval time.Duration + MaxInterval time.Duration + RecursiveDNSServer net.IP + DNSSearchList []string + MTU uint32 +} + +// OVNDHCPOptsSet is an existing DHCP options set in the northbound database. +type OVNDHCPOptsSet struct { + UUID OVNDHCPOptionsUUID + CIDR *net.IPNet +} + +// OVNDHCPv4Opts IPv4 DHCP options that can be applied to a switch port. +type OVNDHCPv4Opts struct { + ServerID net.IP + ServerMAC net.HardwareAddr + Router net.IP + RecursiveDNSServer []net.IP + DomainName string + LeaseTime time.Duration + MTU uint32 + Netmask string +} + +// OVNDHCPv6Opts IPv6 DHCP option set that can be created (and then applied to a switch port by resulting ID). +type OVNDHCPv6Opts struct { + ServerID net.HardwareAddr + RecursiveDNSServer []net.IP + DNSSearchList []string +} + +// OVNSwitchPortOpts options that can be applied to a swich port. +type OVNSwitchPortOpts struct { + MAC net.HardwareAddr // Optional, if nil will be set to dynamic. + IPs []net.IP // Optional, if empty IPs will be set to dynamic. + DHCPv4OptsID OVNDHCPOptionsUUID // Optional, if empty, no DHCPv4 enabled on port. + DHCPv6OptsID OVNDHCPOptionsUUID // Optional, if empty, no DHCPv6 enabled on port. + Parent OVNSwitchPort // Optional, if set a nested port is created. + VLAN uint16 // Optional, use with Parent to request a specific VLAN for nested port. + Location string // Optional, use to indicate the name of the server this port is bound to. +} + +// OVNACLRule represents an ACL rule that can be added to a logical switch or port group. +type OVNACLRule struct { + Direction string // Either "from-lport" or "to-lport". + Action string // Either "allow-related", "allow", "drop", or "reject". + Match string // Match criteria. See OVN Southbound database's Logical_Flow table match column usage. + Priority int // Priority (between 0 and 32767, inclusive). Higher values take precedence. + Log bool // Whether or not to log matched packets. + LogName string // Log label name (requires Log be true). +} + +// OVNLoadBalancerTarget represents an OVN load balancer Virtual IP target. +type OVNLoadBalancerTarget struct { + Address net.IP + Port uint64 +} + +// OVNLoadBalancerVIP represents a OVN load balancer Virtual IP entry. +type OVNLoadBalancerVIP struct { + Protocol string // Either "tcp" or "udp". But only applies to port based VIPs. + ListenAddress net.IP + ListenPort uint64 + Targets []OVNLoadBalancerTarget +} + +// OVNRouterRoute represents a static route added to a logical router. +type OVNRouterRoute struct { + Prefix net.IPNet + NextHop net.IP + Port OVNRouterPort + Discard bool +} + +// OVNRouterPolicy represents a router policy. +type OVNRouterPolicy struct { + Priority int + Match string + Action string + NextHop net.IP +} + +// OVNRouterPeering represents a the configuration of a peering connection between two OVN logical routers. +type OVNRouterPeering struct { + LocalRouter OVNRouter + LocalRouterPort OVNRouterPort + LocalRouterPortMAC net.HardwareAddr + LocalRouterPortIPs []net.IPNet + LocalRouterRoutes []net.IPNet + + TargetRouter OVNRouter + TargetRouterPort OVNRouterPort + TargetRouterPortMAC net.HardwareAddr + TargetRouterPortIPs []net.IPNet + TargetRouterRoutes []net.IPNet +} + +// LogicalRouterAdd adds a named logical router. +func (o *OVN) LogicalRouterAdd(routerName OVNRouter, mayExist bool) error { + args := []string{} + + if mayExist { + args = append(args, "--may-exist") + } + + _, err := o.nbctl(append(args, "lr-add", string(routerName))...) + if err != nil { + return err + } + + return nil +} + +// LogicalRouterDelete deletes a named logical router. +func (o OVN) LogicalRouterDelete(routerName OVNRouter) error { + _, err := o.nbctl("--if-exists", "lr-del", string(routerName)) + if err != nil { + return err + } + + return nil +} + +// LogicalRouterSNATAdd adds an SNAT rule to a logical router to translate packets from intNet to extIP. +func (o *OVN) LogicalRouterSNATAdd(routerName OVNRouter, intNet *net.IPNet, extIP net.IP, mayExist bool) error { + args := []string{} + + if mayExist { + args = append(args, "--if-exists", "lr-nat-del", string(routerName), "snat", extIP.String(), "--") + } + + _, err := o.nbctl(append(args, "lr-nat-add", string(routerName), "snat", extIP.String(), intNet.String())...) + if err != nil { + return err + } + + return nil +} + +// LogicalRouterDNATSNATDeleteAll deletes all DNAT_AND_SNAT rules from a logical router. +func (o *OVN) LogicalRouterDNATSNATDeleteAll(routerName OVNRouter) error { + _, err := o.nbctl("--if-exists", "lr-nat-del", string(routerName), "dnat_and_snat") + if err != nil { + return err + } + + return nil +} + +// LogicalRouterSNATDeleteAll deletes all SNAT rules from a logical router. +func (o *OVN) LogicalRouterSNATDeleteAll(routerName OVNRouter) error { + _, err := o.nbctl("--if-exists", "lr-nat-del", string(routerName), "snat") + if err != nil { + return err + } + + return nil +} + +// LogicalRouterDNATSNATAdd adds a DNAT_AND_SNAT rule to a logical router to translate packets from extIP to intIP. +func (o *OVN) LogicalRouterDNATSNATAdd(routerName OVNRouter, extIP net.IP, intIP net.IP, stateless bool, mayExist bool) error { + if mayExist { + // There appears to be a bug in ovn-nbctl where running lr-nat-del as part of the same command as + // lr-nat-add doesn't take account the changes by lr-nat-del, and so you can end up with errors + // if a NAT entry already exists. So we run them as separate command invocations. + // There can be left over dnat_and_snat entries if an instance was stopped when the ovn-nb DB + // was not reachable. + _, err := o.nbctl("--if-exists", "lr-nat-del", string(routerName), "dnat_and_snat", extIP.String()) + if err != nil { + return err + } + } + + args := []string{} + + if stateless { + args = append(args, "--stateless") + } + + _, err := o.nbctl(append(args, "lr-nat-add", string(routerName), "dnat_and_snat", extIP.String(), intIP.String())...) + if err != nil { + return err + } + + return nil +} + +// LogicalRouterDNATSNATDelete deletes a DNAT_AND_SNAT rule from a logical router. +func (o *OVN) LogicalRouterDNATSNATDelete(routerName OVNRouter, extIPs ...net.IP) error { + args := []string{} + + for _, extIP := range extIPs { + if len(args) > 0 { + args = append(args, "--") + } + + args = append(args, "--if-exists", "lr-nat-del", string(routerName), "dnat_and_snat", extIP.String()) + } + + _, err := o.nbctl(args...) + if err != nil { + return err + } + + return nil +} + +// LogicalRouterRouteAdd adds a static route to the logical router. +func (o *OVN) LogicalRouterRouteAdd(routerName OVNRouter, mayExist bool, routes ...OVNRouterRoute) error { + args := []string{} + + for _, route := range routes { + if len(args) > 0 { + args = append(args, "--") + } + + if mayExist { + args = append(args, "--may-exist") + } + + args = append(args, "lr-route-add", string(routerName), route.Prefix.String()) + + if route.Discard { + args = append(args, "discard") + } else { + args = append(args, route.NextHop.String()) + } + + if route.Port != "" { + args = append(args, string(route.Port)) + } + } + + if len(args) > 0 { + _, err := o.nbctl(args...) + if err != nil { + return err + } + } + + return nil +} + +// LogicalRouterRouteDelete deletes a static route from the logical router. +func (o *OVN) LogicalRouterRouteDelete(routerName OVNRouter, prefixes ...net.IPNet) error { + args := []string{} + + // Delete specific destination routes on router. + for _, prefix := range prefixes { + if len(args) > 0 { + args = append(args, "--") + } + + args = append(args, "--if-exists", "lr-route-del", string(routerName), prefix.String()) + } + + _, err := o.nbctl(args...) + if err != nil { + return err + } + + return nil +} + +// LogicalRouterPortAdd adds a named logical router port to a logical router. +func (o *OVN) LogicalRouterPortAdd(routerName OVNRouter, portName OVNRouterPort, mac net.HardwareAddr, gatewayMTU uint32, ipAddr []*net.IPNet, mayExist bool) error { + if mayExist { + // Check if it exists and update addresses. + _, err := o.nbctl("list", "Logical_Router_Port", string(portName)) + if err == nil { + // Router port exists. + ips := make([]string, 0, len(ipAddr)) + for _, ip := range ipAddr { + ips = append(ips, ip.String()) + } + + _, err := o.nbctl("set", "Logical_Router_Port", string(portName), + fmt.Sprintf(`networks="%s"`, strings.Join(ips, `","`)), + fmt.Sprintf(`mac="%s"`, mac.String()), + fmt.Sprintf("options:gateway_mtu=%d", gatewayMTU), + ) + if err != nil { + return err + } + + return nil + } + } + + args := []string{"lrp-add", string(routerName), string(portName), mac.String()} + for _, ipNet := range ipAddr { + args = append(args, ipNet.String()) + } + + args = append(args, "--", "set", "Logical_Router_Port", string(portName), + fmt.Sprintf(`options:gateway_mtu=%d`, gatewayMTU), + ) + + _, err := o.nbctl(args...) + if err != nil { + return err + } + + return nil +} + +// LogicalRouterPortDelete deletes a named logical router port from a logical router. +func (o *OVN) LogicalRouterPortDelete(portName OVNRouterPort) error { + _, err := o.nbctl("--if-exists", "lrp-del", string(portName)) + if err != nil { + return err + } + + return nil +} + +// LogicalRouterPortSetIPv6Advertisements sets the IPv6 router advertisement options on a router port. +func (o *OVN) LogicalRouterPortSetIPv6Advertisements(portName OVNRouterPort, opts *OVNIPv6RAOpts) error { + args := []string{"set", "logical_router_port", string(portName), + fmt.Sprintf("ipv6_ra_configs:send_periodic=%t", opts.SendPeriodic), + } + + var removeRAConfigKeys []string + + if opts.AddressMode != "" { + args = append(args, fmt.Sprintf("ipv6_ra_configs:address_mode=%s", string(opts.AddressMode))) + } else { + removeRAConfigKeys = append(removeRAConfigKeys, "address_mode") + } + + if opts.MaxInterval > 0 { + args = append(args, fmt.Sprintf("ipv6_ra_configs:max_interval=%d", opts.MaxInterval/time.Second)) + } else { + removeRAConfigKeys = append(removeRAConfigKeys, "max_interval") + } + + if opts.MinInterval > 0 { + args = append(args, fmt.Sprintf("ipv6_ra_configs:min_interval=%d", opts.MinInterval/time.Second)) + } else { + removeRAConfigKeys = append(removeRAConfigKeys, "min_interval") + } + + if opts.MTU > 0 { + args = append(args, fmt.Sprintf("ipv6_ra_configs:mtu=%d", opts.MTU)) + } else { + removeRAConfigKeys = append(removeRAConfigKeys, "mtu") + } + + if len(opts.DNSSearchList) > 0 { + args = append(args, fmt.Sprintf("ipv6_ra_configs:dnssl=%s", strings.Join(opts.DNSSearchList, ","))) + } else { + removeRAConfigKeys = append(removeRAConfigKeys, "dnssl") + } + + if opts.RecursiveDNSServer != nil { + args = append(args, fmt.Sprintf("ipv6_ra_configs:rdnss=%s", opts.RecursiveDNSServer.String())) + } else { + removeRAConfigKeys = append(removeRAConfigKeys, "rdnss") + } + + // Clear any unused keys first. + if len(removeRAConfigKeys) > 0 { + removeArgs := append([]string{"remove", "logical_router_port", string(portName), "ipv6_ra_configs"}, removeRAConfigKeys...) + _, err := o.nbctl(removeArgs...) + if err != nil { + return err + } + } + + // Configure IPv6 Router Advertisements. + _, err := o.nbctl(args...) + if err != nil { + return err + } + + return nil +} + +// LogicalRouterPortDeleteIPv6Advertisements removes the IPv6 RA announcement settings from a router port. +func (o *OVN) LogicalRouterPortDeleteIPv6Advertisements(portName OVNRouterPort) error { + // Delete IPv6 Router Advertisements. + _, err := o.nbctl("clear", "logical_router_port", string(portName), "ipv6_ra_configs") + if err != nil { + return err + } + + return nil +} + +// LogicalRouterPortLinkChassisGroup links a logical router port to a HA chassis group. +func (o *OVN) LogicalRouterPortLinkChassisGroup(portName OVNRouterPort, haChassisGroupName OVNChassisGroup) error { + chassisGroupID, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid", "find", "ha_chassis_group", fmt.Sprintf("name=%s", haChassisGroupName)) + if err != nil { + return err + } + + chassisGroupID = strings.TrimSpace(chassisGroupID) + + if chassisGroupID == "" { + return fmt.Errorf("Chassis group not found") + } + + _, err = o.nbctl("set", "logical_router_port", string(portName), fmt.Sprintf("ha_chassis_group=%s", chassisGroupID)) + if err != nil { + return err + } + + return nil +} + +// LogicalSwitchAdd adds a named logical switch. +// If mayExist is true, then an existing resource of the same name is not treated as an error. +func (o *OVN) LogicalSwitchAdd(switchName OVNSwitch, mayExist bool) error { + args := []string{} + + if mayExist { + args = append(args, "--may-exist") + } + + args = append(args, "ls-add", string(switchName)) + _, err := o.nbctl(args...) + if err != nil { + return err + } + + return nil +} + +// LogicalSwitchDelete deletes a named logical switch. +func (o *OVN) LogicalSwitchDelete(switchName OVNSwitch) error { + args := []string{"--if-exists", "ls-del", string(switchName)} + + assocPortGroups, err := o.logicalSwitchFindAssociatedPortGroups(switchName) + if err != nil { + return err + } + + for _, assocPortGroup := range assocPortGroups { + args = append(args, "--", "destroy", "port_group", string(assocPortGroup)) + } + + _, err = o.nbctl(args...) + if err != nil { + return err + } + + // Remove any existing DHCP options associated to switch. + deleteDHCPRecords, err := o.LogicalSwitchDHCPOptionsGet(switchName) + if err != nil { + return err + } + + if len(deleteDHCPRecords) > 0 { + deleteDHCPUUIDs := make([]OVNDHCPOptionsUUID, 0, len(deleteDHCPRecords)) + for _, deleteDHCPRecord := range deleteDHCPRecords { + deleteDHCPUUIDs = append(deleteDHCPUUIDs, deleteDHCPRecord.UUID) + } + + err = o.LogicalSwitchDHCPOptionsDelete(switchName, deleteDHCPUUIDs...) + if err != nil { + return err + } + } + + err = o.logicalSwitchDNSRecordsDelete(switchName) + if err != nil { + return err + } + + return nil +} + +// logicalSwitchFindAssociatedPortGroups finds the port groups that are associated to the switch specified. +func (o *OVN) logicalSwitchFindAssociatedPortGroups(switchName OVNSwitch) ([]OVNPortGroup, error) { + output, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=name", "find", "port_group", + fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName), + ) + if err != nil { + return nil, err + } + + lines := util.SplitNTrimSpace(strings.TrimSpace(output), "\n", -1, true) + portGroups := make([]OVNPortGroup, 0, len(lines)) + + for _, line := range lines { + portGroups = append(portGroups, OVNPortGroup(line)) + } + + return portGroups, nil +} + +// logicalSwitchParseExcludeIPs parses the ips into OVN exclude_ips format. +func (o *OVN) logicalSwitchParseExcludeIPs(ips []iprange.Range) ([]string, error) { + excludeIPs := make([]string, 0, len(ips)) + for _, v := range ips { + if v.Start == nil || v.Start.To4() == nil { + return nil, fmt.Errorf("Invalid exclude IPv4 range start address") + } else if v.End == nil { + excludeIPs = append(excludeIPs, v.Start.String()) + } else { + if v.End != nil && v.End.To4() == nil { + return nil, fmt.Errorf("Invalid exclude IPv4 range end address") + } + + excludeIPs = append(excludeIPs, fmt.Sprintf("%s..%s", v.Start.String(), v.End.String())) + } + } + + return excludeIPs, nil +} + +// LogicalSwitchSetIPAllocation sets the IP allocation config on the logical switch. +func (o *OVN) LogicalSwitchSetIPAllocation(switchName OVNSwitch, opts *OVNIPAllocationOpts) error { + var removeOtherConfigKeys []string + args := []string{"set", "logical_switch", string(switchName)} + + if opts.PrefixIPv4 != nil { + args = append(args, fmt.Sprintf("other_config:subnet=%s", opts.PrefixIPv4.String())) + } else { + removeOtherConfigKeys = append(removeOtherConfigKeys, "subnet") + } + + if opts.PrefixIPv6 != nil { + args = append(args, fmt.Sprintf("other_config:ipv6_prefix=%s", opts.PrefixIPv6.String())) + } else { + removeOtherConfigKeys = append(removeOtherConfigKeys, "ipv6_prefix") + } + + if len(opts.ExcludeIPv4) > 0 { + excludeIPs, err := o.logicalSwitchParseExcludeIPs(opts.ExcludeIPv4) + if err != nil { + return err + } + + args = append(args, fmt.Sprintf("other_config:exclude_ips=%s", strings.Join(excludeIPs, " "))) + } else { + removeOtherConfigKeys = append(removeOtherConfigKeys, "exclude_ips") + } + + // Clear any unused keys first. + if len(removeOtherConfigKeys) > 0 { + removeArgs := append([]string{"remove", "logical_switch", string(switchName), "other_config"}, removeOtherConfigKeys...) + _, err := o.nbctl(removeArgs...) + if err != nil { + return err + } + } + + // Only run command if at least one setting is specified. + if len(args) > 3 { + _, err := o.nbctl(args...) + if err != nil { + return err + } + } + + return nil +} + +// LogicalSwitchDHCPv4RevervationsSet sets the DHCPv4 IP reservations. +func (o *OVN) LogicalSwitchDHCPv4RevervationsSet(switchName OVNSwitch, reservedIPs []iprange.Range) error { + var removeOtherConfigKeys []string + args := []string{"set", "logical_switch", string(switchName)} + + if len(reservedIPs) > 0 { + excludeIPs, err := o.logicalSwitchParseExcludeIPs(reservedIPs) + if err != nil { + return err + } + + args = append(args, fmt.Sprintf("other_config:exclude_ips=%s", strings.Join(excludeIPs, " "))) + } else { + removeOtherConfigKeys = append(removeOtherConfigKeys, "exclude_ips") + } + + // Clear any unused keys first. + if len(removeOtherConfigKeys) > 0 { + removeArgs := append([]string{"remove", "logical_switch", string(switchName), "other_config"}, removeOtherConfigKeys...) + _, err := o.nbctl(removeArgs...) + if err != nil { + return err + } + } + + // Only run command if at least one setting is specified. + if len(args) > 3 { + _, err := o.nbctl(args...) + if err != nil { + return err + } + } + + return nil +} + +// LogicalSwitchDHCPv4RevervationsGet gets the DHCPv4 IP reservations. +func (o *OVN) LogicalSwitchDHCPv4RevervationsGet(switchName OVNSwitch) ([]iprange.Range, error) { + excludeIPsRaw, err := o.nbctl("--if-exists", "get", "logical_switch", string(switchName), "other_config:exclude_ips") + if err != nil { + return nil, err + } + + excludeIPsRaw = strings.TrimSpace(excludeIPsRaw) + + // Check if no dynamic IPs set. + if excludeIPsRaw == "" || excludeIPsRaw == "[]" { + return []iprange.Range{}, nil + } + + excludeIPsRaw, err = unquote(excludeIPsRaw) + if err != nil { + return nil, fmt.Errorf("Failed unquoting exclude_ips: %w", err) + } + + excludeIPsParts := util.SplitNTrimSpace(strings.TrimSpace(excludeIPsRaw), " ", -1, true) + excludeIPs := make([]iprange.Range, 0, len(excludeIPsParts)) + + for _, excludeIPsPart := range excludeIPsParts { + ip := net.ParseIP(excludeIPsPart) // Check if single IP part. + if ip == nil { + // Check if IP range part. + start, end, found := strings.Cut(excludeIPsPart, "..") + if found { + startIP := net.ParseIP(start) + endIP := net.ParseIP(end) + + if startIP == nil || endIP == nil { + return nil, fmt.Errorf("Invalid exclude_ips range: %q", excludeIPsPart) + } + + // Add range IP part to list. + excludeIPs = append(excludeIPs, iprange.Range{Start: startIP, End: endIP}) + } else { + return nil, fmt.Errorf("Unrecognised exclude_ips part: %q", excludeIPsPart) + } + } else { + // Add single IP part to list. + excludeIPs = append(excludeIPs, iprange.Range{Start: ip}) + } + } + + return excludeIPs, nil +} + +// LogicalSwitchDHCPv4OptionsSet creates or updates a DHCPv4 option set associated with the specified switchName +// and subnet. If uuid is non-empty then the record that exists with that ID is updated, otherwise a new record +// is created. +func (o *OVN) LogicalSwitchDHCPv4OptionsSet(switchName OVNSwitch, uuid OVNDHCPOptionsUUID, subnet *net.IPNet, opts *OVNDHCPv4Opts) error { + var err error + + if uuid != "" { + _, err = o.nbctl("set", "dhcp_option", string(uuid), + fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName), + fmt.Sprintf("cidr=%s", subnet.String()), + ) + if err != nil { + return err + } + } else { + uuidRaw, err := o.nbctl("create", "dhcp_option", + fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName), + fmt.Sprintf("cidr=%s", subnet.String()), + ) + if err != nil { + return err + } + + uuid = OVNDHCPOptionsUUID(strings.TrimSpace(uuidRaw)) + } + + // We have to use dhcp-options-set-options rather than the command above as its the only way to allow the + // domain_name option to be properly escaped. + args := []string{"dhcp-options-set-options", string(uuid), + fmt.Sprintf("server_id=%s", opts.ServerID.String()), + fmt.Sprintf("server_mac=%s", opts.ServerMAC.String()), + fmt.Sprintf("lease_time=%d", opts.LeaseTime/time.Second), + } + + if opts.Router != nil { + args = append(args, fmt.Sprintf("router=%s", opts.Router.String())) + } + + if opts.RecursiveDNSServer != nil { + nsIPs := make([]string, 0, len(opts.RecursiveDNSServer)) + for _, nsIP := range opts.RecursiveDNSServer { + if nsIP.To4() == nil { + continue // Only include IPv4 addresses. + } + + nsIPs = append(nsIPs, nsIP.String()) + } + + args = append(args, fmt.Sprintf("dns_server={%s}", strings.Join(nsIPs, ","))) + } + + if opts.DomainName != "" { + // Special quoting to allow domain names. + args = append(args, fmt.Sprintf(`domain_name="%s"`, opts.DomainName)) + } + + if opts.MTU > 0 { + args = append(args, fmt.Sprintf("mtu=%d", opts.MTU)) + } + + if opts.Netmask != "" { + args = append(args, fmt.Sprintf("netmask=%s", opts.Netmask)) + } + + _, err = o.nbctl(args...) + if err != nil { + return err + } + + return nil +} + +// LogicalSwitchDHCPv6OptionsSet creates or updates a DHCPv6 option set associated with the specified switchName +// and subnet. If uuid is non-empty then the record that exists with that ID is updated, otherwise a new record +// is created. +func (o *OVN) LogicalSwitchDHCPv6OptionsSet(switchName OVNSwitch, uuid OVNDHCPOptionsUUID, subnet *net.IPNet, opts *OVNDHCPv6Opts) error { + var err error + + if uuid != "" { + _, err = o.nbctl("set", "dhcp_option", string(uuid), + fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName), + fmt.Sprintf(`cidr="%s"`, subnet.String()), // Special quoting to allow IPv6 address. + ) + if err != nil { + return err + } + } else { + uuidRaw, err := o.nbctl("create", "dhcp_option", + fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName), + fmt.Sprintf(`cidr="%s"`, subnet.String()), // Special quoting to allow IPv6 address. + ) + if err != nil { + return err + } + + uuid = OVNDHCPOptionsUUID(strings.TrimSpace(uuidRaw)) + } + + // We have to use dhcp-options-set-options rather than the command above as its the only way to allow the + // domain_name option to be properly escaped. + args := []string{"dhcp-options-set-options", string(uuid), + fmt.Sprintf("server_id=%s", opts.ServerID.String()), + } + + if len(opts.DNSSearchList) > 0 { + // Special quoting to allow domain names. + args = append(args, fmt.Sprintf(`domain_search="%s"`, strings.Join(opts.DNSSearchList, ","))) + } + + if opts.RecursiveDNSServer != nil { + nsIPs := make([]string, 0, len(opts.RecursiveDNSServer)) + for _, nsIP := range opts.RecursiveDNSServer { + if nsIP.To4() != nil { + continue // Only include IPv6 addresses. + } + + nsIPs = append(nsIPs, nsIP.String()) + } + + args = append(args, fmt.Sprintf("dns_server={%s}", strings.Join(nsIPs, ","))) + } + + _, err = o.nbctl(args...) + if err != nil { + return err + } + + return nil +} + +// LogicalSwitchDHCPOptionsGet retrieves the existing DHCP options defined for a logical switch. +func (o *OVN) LogicalSwitchDHCPOptionsGet(switchName OVNSwitch) ([]OVNDHCPOptsSet, error) { + output, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid,cidr", "find", "dhcp_options", + fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName), + ) + if err != nil { + return nil, err + } + + colCount := 2 + dhcpOpts := []OVNDHCPOptsSet{} + output = strings.TrimSpace(output) + if output != "" { + for _, row := range strings.Split(output, "\n") { + rowParts := strings.SplitN(row, ",", colCount) + if len(rowParts) < colCount { + return nil, fmt.Errorf("Too few columns in output") + } + + _, cidr, err := net.ParseCIDR(rowParts[1]) + if err != nil { + return nil, err + } + + dhcpOpts = append(dhcpOpts, OVNDHCPOptsSet{ + UUID: OVNDHCPOptionsUUID(rowParts[0]), + CIDR: cidr, + }) + } + } + + return dhcpOpts, nil +} + +// LogicalSwitchDHCPOptionsDelete deletes the specified DHCP options defined for a switch. +func (o *OVN) LogicalSwitchDHCPOptionsDelete(switchName OVNSwitch, uuids ...OVNDHCPOptionsUUID) error { + args := []string{} + + for _, uuid := range uuids { + if len(args) > 0 { + args = append(args, "--") + } + + args = append(args, "destroy", "dhcp_options", string(uuid)) + } + + _, err := o.nbctl(args...) + if err != nil { + return err + } + + return nil +} + +// logicalSwitchDNSRecordsDelete deletes any DNS records defined for a switch. +func (o *OVN) logicalSwitchDNSRecordsDelete(switchName OVNSwitch) error { + uuids, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid", "find", "dns", + fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName), + ) + if err != nil { + return err + } + + args := []string{} + + for _, uuid := range util.SplitNTrimSpace(strings.TrimSpace(uuids), "\n", -1, true) { + if len(args) > 0 { + args = append(args, "--") + } + + args = append(args, "destroy", "dns", uuid) + } + + if len(args) > 0 { + _, err = o.nbctl(args...) + if err != nil { + return err + } + } + + return nil +} + +// LogicalSwitchSetACLRules applies a set of rules to the specified logical switch. Any existing rules are removed. +func (o *OVN) LogicalSwitchSetACLRules(switchName OVNSwitch, aclRules ...OVNACLRule) error { + // Remove any existing rules assigned to the entity. + args := []string{"clear", "logical_switch", string(switchName), "acls"} + + // Add new rules. + externalIDs := map[string]string{ + ovnExtIDIncusSwitch: string(switchName), + } + + args = o.aclRuleAddAppendArgs(args, "logical_switch", string(switchName), externalIDs, nil, aclRules...) + + _, err := o.nbctl(args...) + if err != nil { + return err + } + + return nil +} + +// logicalSwitchPortACLRules returns the ACL rule UUIDs belonging to a logical switch port. +func (o *OVN) logicalSwitchPortACLRules(portName OVNSwitchPort) ([]string, error) { + // Remove any existing rules assigned to the entity. + output, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid", "find", "acl", + fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitchPort, string(portName)), + ) + if err != nil { + return nil, err + } + + ruleUUIDs := util.SplitNTrimSpace(strings.TrimSpace(output), "\n", -1, true) + + return ruleUUIDs, nil +} + +// LogicalSwitchPorts returns a map of logical switch ports (name and UUID) for a switch. +// Includes non-instance ports, such as the router port. +func (o *OVN) LogicalSwitchPorts(switchName OVNSwitch) (map[OVNSwitchPort]OVNSwitchPortUUID, error) { + output, err := o.nbctl("lsp-list", string(switchName)) + if err != nil { + return nil, err + } + + lines := util.SplitNTrimSpace(strings.TrimSpace(output), "\n", -1, true) + ports := make(map[OVNSwitchPort]OVNSwitchPortUUID, len(lines)) + + for _, line := range lines { + // E.g. "c709c4a8-ef3f-4ffe-a45a-c75295eb2698 (incus-net3-instance-fc933d65-0900-46b0-b5f2-4d323342e755-eth0)" + fields := strings.Fields(line) + + if len(fields) != 2 { + return nil, fmt.Errorf("Unrecognised switch port item output %q", line) + } + + portUUID := OVNSwitchPortUUID(fields[0]) + portName := OVNSwitchPort(strings.TrimPrefix(strings.TrimSuffix(fields[1], ")"), "(")) + ports[portName] = portUUID + } + + return ports, nil +} + +// LogicalSwitchIPs returns a list of IPs associated to each port connected to switch. +func (o *OVN) LogicalSwitchIPs(switchName OVNSwitch) (map[OVNSwitchPort][]net.IP, error) { + output, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=name,addresses,dynamic_addresses", "find", "logical_switch_port", + fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName), + ) + if err != nil { + return nil, err + } + + lines := util.SplitNTrimSpace(strings.TrimSpace(output), "\n", -1, true) + portIPs := make(map[OVNSwitchPort][]net.IP, len(lines)) + + for _, line := range lines { + fields := util.SplitNTrimSpace(line, ",", -1, true) + portName := OVNSwitchPort(fields[0]) + var ips []net.IP + + // Parse all IPs mentioned in addresses and dynamic_addresses fields. + for i := 1; i < len(fields); i++ { + for _, address := range util.SplitNTrimSpace(fields[i], " ", -1, true) { + ip := net.ParseIP(address) + if ip != nil { + ips = append(ips, ip) + } + } + } + + portIPs[portName] = ips + } + + return portIPs, nil +} + +// LogicalSwitchPortUUID returns the logical switch port UUID or empty string if port doesn't exist. +func (o *OVN) LogicalSwitchPortUUID(portName OVNSwitchPort) (OVNSwitchPortUUID, error) { + portInfo, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid,name", "find", "logical_switch_port", + fmt.Sprintf("name=%s", string(portName)), + ) + if err != nil { + return "", err + } + + portParts := util.SplitNTrimSpace(portInfo, ",", 2, false) + if len(portParts) == 2 { + if portParts[1] == string(portName) { + return OVNSwitchPortUUID(portParts[0]), nil + } + } + + return "", nil +} + +// LogicalSwitchPortAdd adds a named logical switch port to a logical switch, and sets options if provided. +// If mayExist is true, then an existing resource of the same name is not treated as an error. +func (o *OVN) LogicalSwitchPortAdd(switchName OVNSwitch, portName OVNSwitchPort, opts *OVNSwitchPortOpts, mayExist bool) error { + args := []string{} + + if mayExist { + args = append(args, "--may-exist") + } + + // Add switch port. + args = append(args, "lsp-add", string(switchName), string(portName)) + + // Set switch port options if supplied. + if opts != nil { + // Created nested VLAN port if requested. + if opts.Parent != "" { + args = append(args, string(opts.Parent), fmt.Sprintf("%d", opts.VLAN)) + } + + ipStr := make([]string, 0, len(opts.IPs)) + for _, ip := range opts.IPs { + ipStr = append(ipStr, ip.String()) + } + + var addresses string + if opts.MAC != nil && len(ipStr) > 0 { + addresses = fmt.Sprintf("%s %s", opts.MAC.String(), strings.Join(ipStr, " ")) + } else if opts.MAC != nil && len(ipStr) <= 0 { + addresses = fmt.Sprintf("%s %s", opts.MAC.String(), "dynamic") + } else { + addresses = "dynamic" + } + + args = append(args, "--", "lsp-set-addresses", string(portName), addresses) + + if opts.DHCPv4OptsID != "" { + args = append(args, "--", "lsp-set-dhcpv4-options", string(portName), string(opts.DHCPv4OptsID)) + } + + if opts.DHCPv6OptsID != "" { + args = append(args, "--", "lsp-set-dhcpv6-options", string(portName), string(opts.DHCPv6OptsID)) + } + + if opts.Location != "" { + args = append(args, "--", "set", "logical_switch_port", string(portName), fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusLocation, opts.Location)) + } + } + + args = append(args, "--", "set", "logical_switch_port", string(portName), fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName)) + + _, err := o.nbctl(args...) + if err != nil { + return err + } + + return nil +} + +// LogicalSwitchPortIPs returns a list of IPs for a switch port. +func (o *OVN) LogicalSwitchPortIPs(portName OVNSwitchPort) ([]net.IP, error) { + addressesRaw, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--column=addresses,dynamic_addresses", "find", "logical_switch_port", fmt.Sprintf("name=%s", string(portName))) + if err != nil { + return nil, err + } + + addresses := strings.Split(strings.Replace(strings.TrimSpace(addressesRaw), ",", " ", 1), " ") + ips := make([]net.IP, 0) + + for _, address := range addresses { + ip := net.ParseIP(address) + if ip != nil { + ips = append(ips, ip) + } + } + + return ips, nil +} + +// LogicalSwitchPortDynamicIPs returns a list of dynamc IPs for a switch port. +func (o *OVN) LogicalSwitchPortDynamicIPs(portName OVNSwitchPort) ([]net.IP, error) { + dynamicAddressesRaw, err := o.nbctl("get", "logical_switch_port", string(portName), "dynamic_addresses") + if err != nil { + return nil, err + } + + dynamicAddressesRaw = strings.TrimSpace(dynamicAddressesRaw) + + // Check if no dynamic IPs set. + if dynamicAddressesRaw == "[]" { + return []net.IP{}, nil + } + + dynamicAddressesRaw, err = unquote(dynamicAddressesRaw) + if err != nil { + return nil, fmt.Errorf("Failed unquoting: %w", err) + } + + dynamicAddresses := strings.Split(strings.TrimSpace(dynamicAddressesRaw), " ") + dynamicIPs := make([]net.IP, 0, len(dynamicAddresses)) + + for _, dynamicAddress := range dynamicAddresses { + ip := net.ParseIP(dynamicAddress) + if ip != nil { + dynamicIPs = append(dynamicIPs, ip) + } + } + + return dynamicIPs, nil +} + +// LogicalSwitchPortLocationGet returns the last set location of a logical switch port. +func (o *OVN) LogicalSwitchPortLocationGet(portName OVNSwitchPort) (string, error) { + location, err := o.nbctl("--if-exists", "get", "logical_switch_port", string(portName), fmt.Sprintf("external-ids:%s", ovnExtIDIncusLocation)) + if err != nil { + return "", err + } + + return strings.TrimSpace(location), nil +} + +// LogicalSwitchPortOptionsSet sets the options for a logical switch port. +func (o *OVN) LogicalSwitchPortOptionsSet(portName OVNSwitchPort, options map[string]string) error { + args := []string{"lsp-set-options", string(portName)} + + for key, value := range options { + args = append(args, fmt.Sprintf("%s=%s", key, value)) + } + + _, err := o.nbctl(args...) + if err != nil { + return err + } + + return nil +} + +// LogicalSwitchPortSetDNS sets up the switch port DNS records for the DNS name. +// Returns the DNS record UUID, IPv4 and IPv6 addresses used for DNS records. +func (o *OVN) LogicalSwitchPortSetDNS(switchName OVNSwitch, portName OVNSwitchPort, dnsName string, dnsIPs []net.IP) (OVNDNSUUID, error) { + // Check if existing DNS record exists for switch port. + dnsUUID, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid", "find", "dns", + fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitchPort, portName), + ) + if err != nil { + return "", err + } + + cmdArgs := []string{ + fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName), + fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitchPort, portName), + } + + // Only include DNS name record if IPs supplied. + if len(dnsIPs) > 0 { + var dnsIPsStr strings.Builder + for i, dnsIP := range dnsIPs { + if i > 0 { + dnsIPsStr.WriteString(" ") + } + + dnsIPsStr.WriteString(dnsIP.String()) + } + + cmdArgs = append(cmdArgs, fmt.Sprintf(`records={"%s"="%s"}`, strings.ToLower(dnsName), dnsIPsStr.String())) + } + + dnsUUID = strings.TrimSpace(dnsUUID) + if dnsUUID != "" { + // Clear any existing DNS name if no IPs supplied. + if len(dnsIPs) < 1 { + cmdArgs = append(cmdArgs, "--", "clear", "dns", string(dnsUUID), "records") + } + + // Update existing record if exists. + _, err = o.nbctl(append([]string{"set", "dns", dnsUUID}, cmdArgs...)...) + if err != nil { + return "", err + } + } else { + // Create new record if needed. + dnsUUID, err = o.nbctl(append([]string{"create", "dns"}, cmdArgs...)...) + if err != nil { + return "", err + } + + dnsUUID = strings.TrimSpace(dnsUUID) + } + + // Add DNS record to switch DNS records. + _, err = o.nbctl("add", "logical_switch", string(switchName), "dns_records", dnsUUID) + if err != nil { + return "", err + } + + return OVNDNSUUID(dnsUUID), nil +} + +// LogicalSwitchPortGetDNS returns the logical switch port DNS info (UUID, name and IPs). +func (o *OVN) LogicalSwitchPortGetDNS(portName OVNSwitchPort) (OVNDNSUUID, string, []net.IP, error) { + // Get UUID and DNS IPs for a switch port in the format: ",= " + output, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid,records", "find", "dns", + fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitchPort, portName), + ) + if err != nil { + return "", "", nil, err + } + + parts := strings.Split(strings.TrimSpace(output), ",") + dnsUUID := strings.TrimSpace(parts[0]) + + var dnsName string + var ips []net.IP + + // Try and parse the DNS name and IPs. + if len(parts) > 1 { + dnsParts := strings.SplitN(strings.TrimSpace(parts[1]), "=", 2) + if len(dnsParts) == 2 { + dnsName = strings.TrimSpace(dnsParts[0]) + ipParts := strings.Split(dnsParts[1], " ") + for _, ipPart := range ipParts { + ip := net.ParseIP(strings.TrimSpace(ipPart)) + if ip != nil { + ips = append(ips, ip) + } + } + } + } + + return OVNDNSUUID(dnsUUID), dnsName, ips, nil +} + +// logicalSwitchPortDeleteDNSAppendArgs adds the command arguments to remove DNS records from a switch port. +// If destroyEntry the DNS entry record itself is also removed, otherwise it is just cleared but left in place. +// Returns args with the commands added to it. +func (o *OVN) logicalSwitchPortDeleteDNSAppendArgs(args []string, switchName OVNSwitch, dnsUUID OVNDNSUUID, destroyEntry bool) []string { + if len(args) > 0 { + args = append(args, "--") + } + + args = append(args, "remove", "logical_switch", string(switchName), "dns_records", string(dnsUUID), "--") + + if destroyEntry { + args = append(args, "destroy", "dns", string(dnsUUID)) + } else { + args = append(args, "clear", "dns", string(dnsUUID), "records") + } + + return args +} + +// LogicalSwitchPortDeleteDNS removes DNS records from a switch port. +// If destroyEntry the DNS entry record itself is also removed, otherwise it is just cleared but left in place. +func (o *OVN) LogicalSwitchPortDeleteDNS(switchName OVNSwitch, dnsUUID OVNDNSUUID, destroyEntry bool) error { + // Remove DNS record association from switch, and remove DNS record entry itself. + _, err := o.nbctl(o.logicalSwitchPortDeleteDNSAppendArgs(nil, switchName, dnsUUID, destroyEntry)...) + if err != nil { + return err + } + + return nil +} + +// logicalSwitchPortDeleteAppendArgs adds the commands to delete the specified logical switch port. +// Returns args with the commands added to it. +func (o *OVN) logicalSwitchPortDeleteAppendArgs(args []string, portName OVNSwitchPort) []string { + if len(args) > 0 { + args = append(args, "--") + } + + args = append(args, "--if-exists", "lsp-del", string(portName)) + + return args +} + +// LogicalSwitchPortDelete deletes a named logical switch port. +func (o *OVN) LogicalSwitchPortDelete(portName OVNSwitchPort) error { + _, err := o.nbctl(o.logicalSwitchPortDeleteAppendArgs(nil, portName)...) + if err != nil { + return err + } + + return nil +} + +// LogicalSwitchPortCleanup deletes the named logical switch port and its associated config. +func (o *OVN) LogicalSwitchPortCleanup(portName OVNSwitchPort, switchName OVNSwitch, switchPortGroupName OVNPortGroup, dnsUUID OVNDNSUUID) error { + // Remove any existing rules assigned to the entity. + removeACLRuleUUIDs, err := o.logicalSwitchPortACLRules(portName) + if err != nil { + return err + } + + args := o.aclRuleDeleteAppendArgs(nil, "port_group", string(switchPortGroupName), removeACLRuleUUIDs) + + // Remove logical switch port. + args = o.logicalSwitchPortDeleteAppendArgs(args, portName) + + // Remove DNS records. + if dnsUUID != "" { + args = o.logicalSwitchPortDeleteDNSAppendArgs(args, switchName, dnsUUID, false) + } + + _, err = o.nbctl(args...) + if err != nil { + return err + } + + return nil +} + +// LogicalSwitchPortLinkRouter links a logical switch port to a logical router port. +func (o *OVN) LogicalSwitchPortLinkRouter(switchPortName OVNSwitchPort, routerPortName OVNRouterPort) error { + // Connect logical router port to switch. + _, err := o.nbctl( + "lsp-set-type", string(switchPortName), "router", "--", + "lsp-set-addresses", string(switchPortName), "router", "--", + "lsp-set-options", string(switchPortName), fmt.Sprintf("nat-addresses=%s", "router"), fmt.Sprintf("router-port=%s", string(routerPortName)), + ) + if err != nil { + return err + } + + return nil +} + +// LogicalSwitchPortLinkProviderNetwork links a logical switch port to a provider network. +func (o *OVN) LogicalSwitchPortLinkProviderNetwork(switchPortName OVNSwitchPort, extNetworkName string) error { + // Forward any unknown MAC frames down this port. + _, err := o.nbctl( + "lsp-set-addresses", string(switchPortName), "unknown", "--", + "lsp-set-type", string(switchPortName), "localnet", "--", + "lsp-set-options", string(switchPortName), fmt.Sprintf("network_name=%s", extNetworkName), + ) + if err != nil { + return err + } + + return nil +} + +// ChassisGroupAdd adds a new HA chassis group. +// If mayExist is true, then an existing resource of the same name is not treated as an error. +func (o *OVN) ChassisGroupAdd(haChassisGroupName OVNChassisGroup, mayExist bool) error { + if mayExist { + // Check if it exists (sadly ha-chassis-group-add doesn't provide --may-exist option). + _, err := o.nbctl("list", "HA_Chassis_Group", string(haChassisGroupName)) + if err == nil { + return nil // Chassis group exists. + } + } + + _, err := o.nbctl("ha-chassis-group-add", string(haChassisGroupName)) + if err != nil { + return err + } + + return nil +} + +// ChassisGroupDelete deletes an HA chassis group. +func (o *OVN) ChassisGroupDelete(haChassisGroupName OVNChassisGroup) error { + // ovn-nbctl doesn't provide an "--if-exists" option for removing chassis groups. + existing, err := o.nbctl("--no-headings", "--data=bare", "--colum=name", "find", "ha_chassis_group", fmt.Sprintf("name=%s", string(haChassisGroupName))) + if err != nil { + return err + } + + // Remove chassis group if exists. + if strings.TrimSpace(existing) != "" { + _, err := o.nbctl("ha-chassis-group-del", string(haChassisGroupName)) + if err != nil { + return err + } + } + + return nil +} + +// ChassisGroupChassisAdd adds a chassis ID to an HA chassis group with the specified priority. +func (o *OVN) ChassisGroupChassisAdd(haChassisGroupName OVNChassisGroup, chassisID string, priority uint) error { + _, err := o.nbctl("ha-chassis-group-add-chassis", string(haChassisGroupName), chassisID, fmt.Sprintf("%d", priority)) + if err != nil { + return err + } + + return nil +} + +// ChassisGroupChassisDelete deletes a chassis ID from an HA chassis group. +func (o *OVN) ChassisGroupChassisDelete(haChassisGroupName OVNChassisGroup, chassisID string) error { + // Check if chassis group exists. ovn-nbctl doesn't provide an "--if-exists" option for this. + output, err := o.nbctl("--no-headings", "--data=bare", "--colum=name,ha_chassis", "find", "ha_chassis_group", fmt.Sprintf("name=%s", string(haChassisGroupName))) + if err != nil { + return err + } + + lines := util.SplitNTrimSpace(output, "\n", -1, true) + if len(lines) > 1 { + existingChassisGroup := lines[0] + members := util.SplitNTrimSpace(lines[1], " ", -1, true) + + // Remove chassis from group if exists. + if existingChassisGroup == string(haChassisGroupName) && util.ValueInSlice(chassisID, members) { + _, err := o.nbctl("ha-chassis-group-remove-chassis", string(haChassisGroupName), chassisID) + if err != nil { + return err + } + } + } + + // Nothing to do if chassis group doesn't exist. + return nil +} + +// PortGroupInfo returns the port group UUID or empty string if port doesn't exist, and whether the port group has +// any ACL rules defined on it. +func (o *OVN) PortGroupInfo(portGroupName OVNPortGroup) (OVNPortGroupUUID, bool, error) { + groupInfo, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid,name,acl", "find", "port_group", + fmt.Sprintf("name=%s", string(portGroupName)), + ) + if err != nil { + return "", false, err + } + + groupParts := util.SplitNTrimSpace(groupInfo, ",", 3, true) + if len(groupParts) == 3 { + if groupParts[1] == string(portGroupName) { + aclParts := util.SplitNTrimSpace(groupParts[2], ",", -1, true) + + return OVNPortGroupUUID(groupParts[0]), len(aclParts) > 0, nil + } + } + + return "", false, nil +} + +// PortGroupAdd creates a new port group and optionally adds logical switch ports to the group. +func (o *OVN) PortGroupAdd(projectID int64, portGroupName OVNPortGroup, associatedPortGroup OVNPortGroup, associatedSwitch OVNSwitch, initialPortMembers ...OVNSwitchPort) error { + args := []string{"pg-add", string(portGroupName)} + for _, portName := range initialPortMembers { + args = append(args, string(portName)) + } + + args = append(args, "--", "set", "port_group", string(portGroupName), + fmt.Sprintf("external_ids:%s=%d", ovnExtIDIncusProjectID, projectID), + ) + + if associatedPortGroup != "" || associatedSwitch != "" { + if associatedPortGroup != "" { + args = append(args, fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusPortGroup, associatedPortGroup)) + } + + if associatedSwitch != "" { + args = append(args, fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, associatedSwitch)) + } + } + + _, err := o.nbctl(args...) + if err != nil { + return err + } + + return nil +} + +// PortGroupDelete deletes port groups along with their ACL rules. +func (o *OVN) PortGroupDelete(portGroupNames ...OVNPortGroup) error { + args := make([]string, 0) + + for _, portGroupName := range portGroupNames { + if len(args) > 0 { + args = append(args, "--") + } + + args = append(args, "--if-exists", "destroy", "port_group", string(portGroupName)) + } + + _, err := o.nbctl(args...) + if err != nil { + return err + } + + return nil +} + +// PortGroupListByProject finds the port groups that are associated to the project ID. +func (o *OVN) PortGroupListByProject(projectID int64) ([]OVNPortGroup, error) { + output, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=name", "find", "port_group", + fmt.Sprintf("external_ids:%s=%d", ovnExtIDIncusProjectID, projectID), + ) + if err != nil { + return nil, err + } + + lines := util.SplitNTrimSpace(strings.TrimSpace(output), "\n", -1, true) + portGroups := make([]OVNPortGroup, 0, len(lines)) + + for _, line := range lines { + portGroups = append(portGroups, OVNPortGroup(line)) + } + + return portGroups, nil +} + +// PortGroupMemberChange adds/removes logical switch ports (by UUID) to/from existing port groups. +func (o *OVN) PortGroupMemberChange(addMembers map[OVNPortGroup][]OVNSwitchPortUUID, removeMembers map[OVNPortGroup][]OVNSwitchPortUUID) error { + args := []string{} + + for portGroupName, portMemberUUIDs := range addMembers { + for _, portMemberUUID := range portMemberUUIDs { + if len(args) > 0 { + args = append(args, "--") + } + + args = append(args, "add", "port_group", string(portGroupName), "ports", string(portMemberUUID)) + } + } + + for portGroupName, portMemberUUIDs := range removeMembers { + for _, portMemberUUID := range portMemberUUIDs { + if len(args) > 0 { + args = append(args, "--") + } + + args = append(args, "--if-exists", "remove", "port_group", string(portGroupName), "ports", string(portMemberUUID)) + } + } + + _, err := o.nbctl(args...) + if err != nil { + return err + } + + return nil +} + +// PortGroupSetACLRules applies a set of rules to the specified port group. Any existing rules are removed. +func (o *OVN) PortGroupSetACLRules(portGroupName OVNPortGroup, matchReplace map[string]string, aclRules ...OVNACLRule) error { + // Remove any existing rules assigned to the entity. + args := []string{"clear", "port_group", string(portGroupName), "acls"} + + // Add new rules. + externalIDs := map[string]string{ + ovnExtIDIncusPortGroup: string(portGroupName), + } + + args = o.aclRuleAddAppendArgs(args, "port_group", string(portGroupName), externalIDs, matchReplace, aclRules...) + + _, err := o.nbctl(args...) + if err != nil { + return err + } + + return nil +} + +// aclRuleAddAppendArgs adds the commands to args that add the provided ACL rules to the specified OVN entity. +// Returns args with the ACL rule add commands added to it. +func (o *OVN) aclRuleAddAppendArgs(args []string, entityTable string, entityName string, externalIDs map[string]string, matchReplace map[string]string, aclRules ...OVNACLRule) []string { + for i, rule := range aclRules { + if len(args) > 0 { + args = append(args, "--") + } + + // Perform any replacements requested on the Match string. + for find, replace := range matchReplace { + rule.Match = strings.ReplaceAll(rule.Match, find, replace) + } + + // Add command to create ACL rule. + args = append(args, fmt.Sprintf("--id=@id%d", i), "create", "acl", + fmt.Sprintf("action=%s", rule.Action), + fmt.Sprintf("direction=%s", rule.Direction), + fmt.Sprintf("priority=%d", rule.Priority), + fmt.Sprintf("match=%s", strconv.Quote(rule.Match)), + ) + + if rule.Log { + args = append(args, "log=true") + + if rule.LogName != "" { + args = append(args, fmt.Sprintf("name=%s", rule.LogName)) + } + } + + for k, v := range externalIDs { + args = append(args, fmt.Sprintf("external_ids:%s=%s", k, v)) + } + + // Add command to assign ACL rule to entity. + args = append(args, "--", "add", entityTable, entityName, "acl", fmt.Sprintf("@id%d", i)) + } + + return args +} + +// aclRuleDeleteAppendArgs adds the commands to args that delete the provided ACL rules from the specified OVN entity. +// Returns args with the ACL rule delete commands added to it. +func (o *OVN) aclRuleDeleteAppendArgs(args []string, entityTable string, entityName string, aclRuleUUIDs []string) []string { + for _, aclRuleUUID := range aclRuleUUIDs { + if len(args) > 0 { + args = append(args, "--") + } + + args = append(args, "remove", entityTable, string(entityName), "acl", aclRuleUUID) + } + + return args +} + +// PortGroupPortSetACLRules applies a set of rules for the logical switch port in the specified port group. +// Any existing rules for that logical switch port in the port group are removed. +func (o *OVN) PortGroupPortSetACLRules(portGroupName OVNPortGroup, portName OVNSwitchPort, aclRules ...OVNACLRule) error { + // Remove any existing rules assigned to the entity. + removeACLRuleUUIDs, err := o.logicalSwitchPortACLRules(portName) + if err != nil { + return err + } + + args := o.aclRuleDeleteAppendArgs(nil, "port_group", string(portGroupName), removeACLRuleUUIDs) + + // Add new rules. + externalIDs := map[string]string{ + ovnExtIDIncusPortGroup: string(portGroupName), + ovnExtIDIncusSwitchPort: string(portName), + } + + args = o.aclRuleAddAppendArgs(args, "port_group", string(portGroupName), externalIDs, nil, aclRules...) + + _, err = o.nbctl(args...) + if err != nil { + return err + } + + return nil +} + +// PortGroupPortClearACLRules clears any rules assigned to the logical switch port in the specified port group. +func (o *OVN) PortGroupPortClearACLRules(portGroupName OVNPortGroup, portName OVNSwitchPort) error { + // Remove any existing rules assigned to the entity. + removeACLRuleUUIDs, err := o.logicalSwitchPortACLRules(portName) + if err != nil { + return err + } + + args := o.aclRuleDeleteAppendArgs(nil, "port_group", string(portGroupName), removeACLRuleUUIDs) + + if len(args) > 0 { + _, err = o.nbctl(args...) + if err != nil { + return err + } + } + + return nil +} + +// LoadBalancerApply creates a new load balancer (if doesn't exist) on the specified routers and switches. +// Providing an empty set of vips will delete the load balancer. +func (o *OVN) LoadBalancerApply(loadBalancerName OVNLoadBalancer, routers []OVNRouter, switches []OVNSwitch, vips ...OVNLoadBalancerVIP) error { + lbTCPName := fmt.Sprintf("%s-tcp", loadBalancerName) + lbUDPName := fmt.Sprintf("%s-udp", loadBalancerName) + + // Remove existing load balancers if they exist. + args := []string{"--if-exists", "lb-del", lbTCPName, "--", "lb-del", lbUDPName} + + // ipToString wraps IPv6 addresses in square brackets. + ipToString := func(ip net.IP) string { + if ip.To4() == nil { + return fmt.Sprintf("[%s]", ip.String()) + } + + return ip.String() + } + + // We have to use a separate load balancer for UDP rules so use this to keep track of whether we need it. + lbNames := make(map[string]struct{}) + + // Build up the commands to add VIPs to the load balancer. + for _, r := range vips { + if r.ListenAddress == nil { + return fmt.Errorf("Missing VIP listen address") + } + + if len(r.Targets) == 0 { + return fmt.Errorf("Missing VIP target(s)") + } + + if r.Protocol == "udp" { + args = append(args, "--", "lb-add", lbUDPName) + lbNames[lbUDPName] = struct{}{} // Record that UDP load balancer is created. + } else { + args = append(args, "--", "lb-add", lbTCPName) + lbNames[lbTCPName] = struct{}{} // Record that TCP load balancer is created. + } + + targetArgs := make([]string, 0, len(r.Targets)) + + for _, target := range r.Targets { + if (r.ListenPort > 0 && target.Port <= 0) || (target.Port > 0 && r.ListenPort <= 0) { + return fmt.Errorf("The listen and target ports must be specified together") + } + + if r.ListenPort > 0 { + targetArgs = append(targetArgs, fmt.Sprintf("%s:%d", ipToString(target.Address), target.Port)) + } else { + targetArgs = append(targetArgs, ipToString(target.Address)) + } + } + + if r.ListenPort > 0 { + args = append(args, + fmt.Sprintf("%s:%d", ipToString(r.ListenAddress), r.ListenPort), + strings.Join(targetArgs, ","), + r.Protocol, + ) + } else { + args = append(args, + ipToString(r.ListenAddress), + strings.Join(targetArgs, ","), + ) + } + } + + // If there are some VIP rules then associate the load balancer to the requested routers and switches. + if len(vips) > 0 { + for _, r := range routers { + _, found := lbNames[lbTCPName] + if found { + args = append(args, "--", "lr-lb-add", string(r), lbTCPName) + } + + _, found = lbNames[lbUDPName] + if found { + args = append(args, "--", "lr-lb-add", string(r), lbUDPName) + } + } + + for _, s := range switches { + _, found := lbNames[lbTCPName] + if found { + args = append(args, "--", "ls-lb-add", string(s), lbTCPName) + } + + _, found = lbNames[lbUDPName] + if found { + args = append(args, "--", "ls-lb-add", string(s), lbUDPName) + } + } + } + + _, err := o.nbctl(args...) + if err != nil { + return err + } + + return nil +} + +// LoadBalancerDelete deletes the specified load balancer(s). +func (o *OVN) LoadBalancerDelete(loadBalancerNames ...OVNLoadBalancer) error { + var args []string + + for _, loadBalancerName := range loadBalancerNames { + if len(args) > 0 { + args = append(args, "--") + } + + lbTCPName := fmt.Sprintf("%s-tcp", loadBalancerName) + lbUDPName := fmt.Sprintf("%s-udp", loadBalancerName) + + // Remove load balancers for loadBalancerName if they exist. + args = append(args, "--if-exists", "lb-del", lbTCPName, "--", "lb-del", lbUDPName) + } + + if len(args) > 0 { + _, err := o.nbctl(args...) + if err != nil { + return err + } + } + + return nil +} + +// AddressSetCreate creates address sets for IP versions 4 and 6 in the format "_ip". +// Populates them with the relevant addresses supplied. +func (o *OVN) AddressSetCreate(addressSetPrefix OVNAddressSet, addresses ...net.IPNet) error { + args := []string{ + "create", "address_set", fmt.Sprintf("name=%s_ip%d", addressSetPrefix, 4), + "--", "create", "address_set", fmt.Sprintf("name=%s_ip%d", addressSetPrefix, 6), + } + + for _, address := range addresses { + if len(args) > 0 { + args = append(args, "--") + } + + var ipVersion uint = 4 + if address.IP.To4() == nil { + ipVersion = 6 + } + + args = append(args, "add", "address_set", fmt.Sprintf("%s_ip%d", addressSetPrefix, ipVersion), "addresses", fmt.Sprintf(`"%s"`, address.String())) + } + + if len(args) > 0 { + _, err := o.nbctl(args...) + if err != nil { + return err + } + } + + return nil +} + +// AddressSetAdd adds the supplied addresses to the address sets, or creates a new address sets if needed. +// The address set name used is "_ip", e.g. "foo_ip4". +func (o *OVN) AddressSetAdd(addressSetPrefix OVNAddressSet, addresses ...net.IPNet) error { + var args []string + ipVersions := make(map[uint]struct{}) + + for _, address := range addresses { + if len(args) > 0 { + args = append(args, "--") + } + + var ipVersion uint = 4 + if address.IP.To4() == nil { + ipVersion = 6 + } + + // Track IP versions seen so we can create address sets if needed. + ipVersions[ipVersion] = struct{}{} + + args = append(args, "add", "address_set", fmt.Sprintf("%s_ip%d", addressSetPrefix, ipVersion), "addresses", fmt.Sprintf(`"%s"`, address.String())) + } + + if len(args) > 0 { + // Optimistically assume all required address sets exist (they normally will). + _, err := o.nbctl(args...) + if err != nil { + // Try creating the address sets one at a time, but ignore errors here in case some of the + // address sets already exist. If there was a problem creating the address set it will be + // revealead when we run the original command again next. + for ipVersion := range ipVersions { + _, _ = o.nbctl("create", "address_set", fmt.Sprintf("name=%s_ip%d", addressSetPrefix, ipVersion)) + } + + // Try original command again. + _, err := o.nbctl(args...) + if err != nil { + return err + } + } + } + + return nil +} + +// AddressSetRemove removes the supplied addresses from the address set. +// The address set name used is "_ip", e.g. "foo_ip4". +func (o *OVN) AddressSetRemove(addressSetPrefix OVNAddressSet, addresses ...net.IPNet) error { + var args []string + + for _, address := range addresses { + if len(args) > 0 { + args = append(args, "--") + } + + var ipVersion uint = 4 + if address.IP.To4() == nil { + ipVersion = 6 + } + + args = append(args, "--if-exists", "remove", "address_set", fmt.Sprintf("%s_ip%d", addressSetPrefix, ipVersion), "addresses", fmt.Sprintf(`"%s"`, address.String())) + } + + if len(args) > 0 { + _, err := o.nbctl(args...) + if err != nil { + return err + } + } + + return nil +} + +// AddressSetDelete deletes address sets for IP versions 4 and 6 in the format "_ip". +func (o *OVN) AddressSetDelete(addressSetPrefix OVNAddressSet) error { + _, err := o.nbctl( + "--if-exists", "destroy", "address_set", fmt.Sprintf("%s_ip%d", addressSetPrefix, 4), + "--", "--if-exists", "destroy", "address_set", fmt.Sprintf("%s_ip%d", addressSetPrefix, 6), + ) + if err != nil { + return err + } + + return nil +} + +// LogicalRouterPolicyApply removes any existing policies and applies the new policies to the specified router. +func (o *OVN) LogicalRouterPolicyApply(routerName OVNRouter, policies ...OVNRouterPolicy) error { + args := []string{"lr-policy-del", string(routerName)} + + for _, policy := range policies { + args = append(args, "--", "lr-policy-add", string(routerName), fmt.Sprintf("%d", policy.Priority), policy.Match, policy.Action) + } + + _, err := o.nbctl(args...) + if err != nil { + return err + } + + return nil +} + +// LogicalRouterRoutes returns a list of static routes in the main route table of the logical router. +func (o *OVN) LogicalRouterRoutes(routerName OVNRouter) ([]OVNRouterRoute, error) { + output, err := o.nbctl("lr-route-list", string(routerName)) + if err != nil { + return nil, err + } + + lines := util.SplitNTrimSpace(strings.TrimSpace(output), "\n", -1, true) + routes := make([]OVNRouterRoute, 0) + + mainTable := true // Assume output starts with main table (supports ovn versions without multiple tables). + for i, line := range lines { + if line == "IPv4 Routes" || line == "IPv6 Routes" { + continue // Ignore heading category lines. + } + + // Keep track of which route table we are looking at. + if strings.HasPrefix(line, "Route Table") { + if line == "Route Table
:" { + mainTable = true + } else { + mainTable = false + } + + continue + } + + if !mainTable { + continue // We don't currently consider routes in other route tables. + } + + // E.g. "10.97.31.0/24 10.97.31.1 dst-ip [optional-some-router-port-name]" + fields := strings.Fields(line) + fieldsLen := len(fields) + + if fieldsLen <= 0 { + continue // Ignore empty lines. + } else if fieldsLen < 3 || fieldsLen > 4 { + return nil, fmt.Errorf("Unrecognised static route item output on line %d: %q", i, line) + } + + var route OVNRouterRoute + + // ovn-nbctl doesn't output single-host route prefixes in CIDR format, so do the conversion here. + ip := net.ParseIP(fields[0]) + if ip != nil { + subnetSize := 32 + if ip.To4() == nil { + subnetSize = 128 + } + + fields[0] = fmt.Sprintf("%s/%d", ip.String(), subnetSize) + } + + _, prefix, err := net.ParseCIDR(fields[0]) + if err != nil { + return nil, fmt.Errorf("Invalid static route prefix on line %d: %q", i, fields[0]) + } + + route.Prefix = *prefix + route.NextHop = net.ParseIP(fields[1]) + + if fieldsLen > 3 { + route.Port = OVNRouterPort(fields[3]) + } + + routes = append(routes, route) + } + + return routes, nil +} + +// LogicalRouterPeeringApply applies a peering relationship between two logical routers. +func (o *OVN) LogicalRouterPeeringApply(opts OVNRouterPeering) error { + if len(opts.LocalRouterPortIPs) <= 0 || len(opts.TargetRouterPortIPs) <= 0 { + return fmt.Errorf("IPs not populated for both router ports") + } + + // Remove peering router ports and static routes using ports from both routers. + // Run the delete step as a separate command to workaround a bug in OVN. + err := o.LogicalRouterPeeringDelete(opts) + if err != nil { + return err + } + + // Start fresh command set. + var args []string + + // Will use the first IP from each family of the router port interfaces. + localRouterGatewayIPs := make(map[uint]net.IP, 0) + targetRouterGatewayIPs := make(map[uint]net.IP, 0) + + // Setup local router port peered with target router port. + args = append(args, "--", "lrp-add", string(opts.LocalRouter), string(opts.LocalRouterPort), opts.LocalRouterPortMAC.String()) + for _, ipNet := range opts.LocalRouterPortIPs { + ipVersion := uint(4) + if ipNet.IP.To4() == nil { + ipVersion = 6 + } + + if localRouterGatewayIPs[ipVersion] == nil { + localRouterGatewayIPs[ipVersion] = ipNet.IP + } + + args = append(args, ipNet.String()) + } + + args = append(args, fmt.Sprintf("peer=%s", opts.TargetRouterPort)) + + // Setup target router port peered with local router port. + args = append(args, "--", "lrp-add", string(opts.TargetRouter), string(opts.TargetRouterPort), opts.TargetRouterPortMAC.String()) + for _, ipNet := range opts.TargetRouterPortIPs { + ipVersion := uint(4) + if ipNet.IP.To4() == nil { + ipVersion = 6 + } + + if targetRouterGatewayIPs[ipVersion] == nil { + targetRouterGatewayIPs[ipVersion] = ipNet.IP + } + + args = append(args, ipNet.String()) + } + + args = append(args, fmt.Sprintf("peer=%s", opts.LocalRouterPort)) + + // Add routes using the first router gateway IP for each family for next hop address. + for _, route := range opts.LocalRouterRoutes { + ipVersion := uint(4) + if route.IP.To4() == nil { + ipVersion = 6 + } + + nextHopIP := targetRouterGatewayIPs[ipVersion] + + if nextHopIP == nil { + return fmt.Errorf("Missing target router port IPv%d address for local route %q nexthop address", ipVersion, route.String()) + } + + args = append(args, "--", "--may-exist", "lr-route-add", string(opts.LocalRouter), route.String(), nextHopIP.String(), string(opts.LocalRouterPort)) + } + + for _, route := range opts.TargetRouterRoutes { + ipVersion := uint(4) + if route.IP.To4() == nil { + ipVersion = 6 + } + + nextHopIP := localRouterGatewayIPs[ipVersion] + + if nextHopIP == nil { + return fmt.Errorf("Missing local router port IPv%d address for target route %q nexthop address", ipVersion, route.String()) + } + + args = append(args, "--", "--may-exist", "lr-route-add", string(opts.TargetRouter), route.String(), nextHopIP.String(), string(opts.TargetRouterPort)) + } + + if len(args) > 0 { + _, err := o.nbctl(args...) + if err != nil { + return err + } + } + + return nil +} + +// LogicalRouterPeeringDelete deletes a peering relationship between two logical routers. +// Requires LocalRouter, LocalRouterPort, TargetRouter and TargetRouterPort opts fields to be populated. +func (o *OVN) LogicalRouterPeeringDelete(opts OVNRouterPeering) error { + // Remove peering router ports and static routes using ports from both routers. + if opts.LocalRouter == "" || opts.TargetRouter == "" { + return fmt.Errorf("Router names not populated for both routers") + } + + args := []string{ + "--if-exists", "lrp-del", string(opts.LocalRouterPort), "--", + "--if-exists", "lrp-del", string(opts.TargetRouterPort), + } + + // Remove static routes from both routers that use the respective peering router ports. + staticRoutes, err := o.LogicalRouterRoutes(opts.LocalRouter) + if err != nil { + return fmt.Errorf("Failed getting static routes for local peer router %q: %w", opts.LocalRouter, err) + } + + for _, staticRoute := range staticRoutes { + if staticRoute.Port == opts.LocalRouterPort { + args = append(args, "--", "lr-route-del", string(opts.LocalRouter), staticRoute.Prefix.String(), staticRoute.NextHop.String(), string(opts.LocalRouterPort)) + } + } + + staticRoutes, err = o.LogicalRouterRoutes(opts.TargetRouter) + if err != nil { + return fmt.Errorf("Failed getting static routes for target peer router %q: %w", opts.TargetRouter, err) + } + + for _, staticRoute := range staticRoutes { + if staticRoute.Port == opts.TargetRouterPort { + args = append(args, "--", "lr-route-del", string(opts.TargetRouter), staticRoute.Prefix.String(), staticRoute.NextHop.String(), string(opts.TargetRouterPort)) + } + } + + if len(args) > 0 { + _, err := o.nbctl(args...) + if err != nil { + return err + } + } + + return nil +} + +// GetHardwareAddress gets the hardware address of the logical router port. +func (o *OVN) GetHardwareAddress(ovnRouterPort OVNRouterPort) (string, error) { + nameFilter := fmt.Sprintf("name=%s", ovnRouterPort) + hwaddr, err := o.nbctl("--no-headings", "--data=bare", "--format=csv", "--columns=mac", "find", "Logical_Router_Port", nameFilter) + if err != nil { + return "", err + } + + return strings.TrimSpace(hwaddr), nil +} + +// GetLogicalRouterPortActiveChassisHostname gets the hostname of the chassis managing the logical router port. +func (o *OVN) GetLogicalRouterPortActiveChassisHostname(ovnRouterPort OVNRouterPort) (string, error) { + // Get the chassis ID from port bindings where the logical port is a chassis redirect (prepended "cr-") of the logical router port name. + filter := fmt.Sprintf("logical_port=cr-%s", ovnRouterPort) + chassisID, err := o.sbctl("--no-headings", "--columns=chassis", "--data=bare", "--format=csv", "find", "Port_Binding", filter) + if err != nil { + return "", err + } + + hostname, err := o.sbctl("get", "Chassis", strings.TrimSpace(chassisID), "hostname") + if err != nil { + return "", err + } + + return strings.TrimSpace(hostname), err +} From d87d46523c7453932578b1cab42c874f724c34c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Mon, 18 Dec 2023 14:01:47 -0500 Subject: [PATCH 07/38] incusd/network/openvswitch: Add OVN database types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- internal/server/network/openvswitch/ovn.go | 24 ++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/internal/server/network/openvswitch/ovn.go b/internal/server/network/openvswitch/ovn.go index 9ab82bfa2d7..edff6e9d346 100644 --- a/internal/server/network/openvswitch/ovn.go +++ b/internal/server/network/openvswitch/ovn.go @@ -87,6 +87,12 @@ type OVN struct { sslClientKey string } +// ovnDatabase represents the OVN database to connect to. +type ovnDatabase string + +const ovnDatabaseNorthbound = ovnDatabase("nortbound") +const ovnDatabaseSouthbound = ovnDatabase("southbound") + // getNorthboundDB returns connection string to use for northbound database. func (o *OVN) getNorthboundDB() string { if o.nbDBAddr == "" { @@ -107,21 +113,27 @@ func (o *OVN) getSouthboundDB() string { // sbctl executes ovn-sbctl with arguments to connect to wrapper's southbound database. func (o *OVN) sbctl(args ...string) (string, error) { - return o.xbctl(true, args...) + return o.xbctl(ovnDatabaseSouthbound, args...) } // nbctl executes ovn-nbctl with arguments to connect to wrapper's northbound database. func (o *OVN) nbctl(args ...string) (string, error) { - return o.xbctl(false, append([]string{"--wait=sb"}, args...)...) + return o.xbctl(ovnDatabaseNorthbound, append([]string{"--wait=sb"}, args...)...) } // xbctl optionally executes either ovn-nbctl or ovn-sbctl with arguments to connect to wrapper's northbound or southbound database. -func (o *OVN) xbctl(southbound bool, extraArgs ...string) (string, error) { - dbAddr := o.getNorthboundDB() - cmd := "ovn-nbctl" - if southbound { +func (o *OVN) xbctl(database ovnDatabase, extraArgs ...string) (string, error) { + // Figure out the command. + var dbAddr string + var cmd string + if database == ovnDatabaseNorthbound { + dbAddr = o.getNorthboundDB() + cmd = "ovn-nbctl" + } else if database == ovnDatabaseSouthbound { dbAddr = o.getSouthboundDB() cmd = "ovn-sbctl" + } else { + return "", fmt.Errorf("Unsupported database type %q", database) } // Figure out args. From 6e6f25a6687fb62d03e206cf40d7ac08995b1fbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Mon, 18 Dec 2023 14:40:26 -0500 Subject: [PATCH 08/38] incusd/network/openvswitch: Add native ovsdb client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- internal/server/network/openvswitch/ovn.go | 161 +++++++++++++++++++++ 1 file changed, 161 insertions(+) diff --git a/internal/server/network/openvswitch/ovn.go b/internal/server/network/openvswitch/ovn.go index edff6e9d346..5106a06ea53 100644 --- a/internal/server/network/openvswitch/ovn.go +++ b/internal/server/network/openvswitch/ovn.go @@ -2,11 +2,21 @@ package openvswitch import ( "context" + "crypto/tls" + "crypto/x509" + "encoding/pem" "fmt" "os" "strings" + "sync" + + "github.com/go-logr/logr" + ovsdbClient "github.com/ovn-org/libovsdb/client" + ovsdbModel "github.com/ovn-org/libovsdb/model" "github.com/lxc/incus/internal/linux" + ovnNB "github.com/lxc/incus/internal/server/network/openvswitch/schema/ovn-nb" + ovnSB "github.com/lxc/incus/internal/server/network/openvswitch/schema/ovn-sb" "github.com/lxc/incus/internal/server/state" "github.com/lxc/incus/shared/subprocess" ) @@ -79,12 +89,21 @@ func NewOVN(s *state.State) (*OVN, error) { // OVN command wrapper. type OVN struct { + mu sync.Mutex + nbDBAddr string sbDBAddr string sslCACert string sslClientCert string sslClientKey string + + ovsdbClient map[ovnDatabase]*ovnClient +} + +type ovnClient struct { + client ovsdbClient.Client + group sync.WaitGroup } // ovnDatabase represents the OVN database to connect to. @@ -93,6 +112,148 @@ type ovnDatabase string const ovnDatabaseNorthbound = ovnDatabase("nortbound") const ovnDatabaseSouthbound = ovnDatabase("southbound") +func (o *OVN) client(database ovnDatabase) (ovsdbClient.Client, func(), error) { + // Check if we already have a client. + o.mu.Lock() + defer o.mu.Unlock() + client, ok := o.ovsdbClient[database] + if ok { + client.group.Add(1) + return client.client, func() { client.group.Done() }, nil + } + + // Figure out the database address and schema. + var dbAddr string + var dbSchema ovsdbModel.ClientDBModel + + if database == ovnDatabaseNorthbound { + var err error + dbAddr = o.getNorthboundDB() + + dbSchema, err = ovnNB.FullDatabaseModel() + if err != nil { + return nil, nil, err + } + } else if database == ovnDatabaseSouthbound { + var err error + dbAddr = o.getSouthboundDB() + + dbSchema, err = ovnSB.FullDatabaseModel() + if err != nil { + return nil, nil, err + } + } else { + return nil, nil, fmt.Errorf("Unsupported database type %q", database) + } + + // Prepare the client. + discard := logr.Discard() + + options := []ovsdbClient.Option{ovsdbClient.WithLogger(&discard)} + for _, entry := range strings.Split(dbAddr, ",") { + options = append(options, ovsdbClient.WithEndpoint(entry)) + } + + // Handle SSL. + if strings.Contains(dbAddr, "ssl:") { + clientCert, err := tls.X509KeyPair([]byte(o.sslClientCert), []byte(o.sslClientKey)) + if err != nil { + return nil, nil, err + } + + tlsConfig := &tls.Config{ + Certificates: []tls.Certificate{clientCert}, + InsecureSkipVerify: true, + } + + // If provided with a CA certificate, setup a validator for the cert chain (but not the name). + if o.sslCACert != "" { + tlsCAder, _ := pem.Decode([]byte(o.sslCACert)) + if tlsCAder == nil { + return nil, nil, fmt.Errorf("Couldn't parse CA certificate") + } + + tlsCAcert, err := x509.ParseCertificate(tlsCAder.Bytes) + if err != nil { + return nil, nil, err + } + + tlsCAcert.IsCA = true + tlsCAcert.KeyUsage = x509.KeyUsageCertSign + + clientCAPool := x509.NewCertPool() + clientCAPool.AddCert(tlsCAcert) + + tlsConfig.VerifyPeerCertificate = func(rawCerts [][]byte, chains [][]*x509.Certificate) error { + if len(rawCerts) < 1 { + return fmt.Errorf("Missing server certificate") + } + + // Load the chain. + roots := x509.NewCertPool() + for _, rawCert := range rawCerts { + cert, _ := x509.ParseCertificate(rawCert) + if cert != nil { + roots.AddCert(cert) + } + } + + // Load the main server certificate. + cert, _ := x509.ParseCertificate(rawCerts[0]) + if cert == nil { + return fmt.Errorf("Bad server certificate") + } + + // Validate. + opts := x509.VerifyOptions{ + Roots: roots, + } + + _, err := cert.Verify(opts) + return err + } + } + + options = append(options, ovsdbClient.WithTLSConfig(tlsConfig)) + } + + ovn, err := ovsdbClient.NewOVSDBClient(dbSchema, options...) + if err != nil { + return nil, nil, err + } + + err = ovn.Connect(context.Background()) + if err != nil { + return nil, nil, err + } + + err = ovn.Echo(context.TODO()) + if err != nil { + return nil, nil, err + } + + monitorCookie, err := ovn.MonitorAll(context.TODO()) + if err != nil { + return nil, nil, err + } + + dbClient := &ovnClient{ + client: ovn, + group: sync.WaitGroup{}, + } + + dbClient.group.Add(1) + + go func() { + dbClient.group.Wait() + _ = ovn.MonitorCancel(context.TODO(), monitorCookie) + }() + + o.ovsdbClient[database] = dbClient + + return ovn, func() { dbClient.group.Done() }, nil +} + // getNorthboundDB returns connection string to use for northbound database. func (o *OVN) getNorthboundDB() string { if o.nbDBAddr == "" { From fd82c99ebf8b86cdb4ee8a19686a3bacd81b3db1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Mon, 18 Dec 2023 14:48:59 -0500 Subject: [PATCH 09/38] incusd/network/openvswitch: Simplify logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- .../server/network/openvswitch/ovn_actions.go | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/internal/server/network/openvswitch/ovn_actions.go b/internal/server/network/openvswitch/ovn_actions.go index aa785738299..5f7eff4a05f 100644 --- a/internal/server/network/openvswitch/ovn_actions.go +++ b/internal/server/network/openvswitch/ovn_actions.go @@ -700,19 +700,19 @@ func (o *OVN) LogicalSwitchDHCPv4RevervationsGet(switchName OVNSwitch) ([]iprang if ip == nil { // Check if IP range part. start, end, found := strings.Cut(excludeIPsPart, "..") - if found { - startIP := net.ParseIP(start) - endIP := net.ParseIP(end) + if !found { + return nil, fmt.Errorf("Unrecognised exclude_ips part: %q", excludeIPsPart) + } - if startIP == nil || endIP == nil { - return nil, fmt.Errorf("Invalid exclude_ips range: %q", excludeIPsPart) - } + startIP := net.ParseIP(start) + endIP := net.ParseIP(end) - // Add range IP part to list. - excludeIPs = append(excludeIPs, iprange.Range{Start: startIP, End: endIP}) - } else { - return nil, fmt.Errorf("Unrecognised exclude_ips part: %q", excludeIPsPart) + if startIP == nil || endIP == nil { + return nil, fmt.Errorf("Invalid exclude_ips range: %q", excludeIPsPart) } + + // Add range IP part to list. + excludeIPs = append(excludeIPs, iprange.Range{Start: startIP, End: endIP}) } else { // Add single IP part to list. excludeIPs = append(excludeIPs, iprange.Range{Start: ip}) From 22515153deb5e568dcb118f966b4005cbca44192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Mon, 18 Dec 2023 14:51:38 -0500 Subject: [PATCH 10/38] golangci: Don't complain about unused receivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- .golangci.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 968dcb10c07..bd38500426c 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -32,9 +32,6 @@ linters-settings: - "checkPrivateReceivers" - "disableStutteringCheck" - # https://github.com/mgechev/revive/blob/2a1701aadbedfcc175cb92836a51407bec382652/RULES_DESCRIPTIONS.md#unused-receiver - - name: unused-receiver - # https://github.com/mgechev/revive/blob/2a1701aadbedfcc175cb92836a51407bec382652/RULES_DESCRIPTIONS.md#import-shadowing - name: import-shadowing From 757148099e1cf904bb96b1748184cd55e4092d1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Mon, 18 Dec 2023 14:57:57 -0500 Subject: [PATCH 11/38] incusd/network/openvswitch: Use pointer receiver for LogicalRouterDelete MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- internal/server/network/openvswitch/ovn_actions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/server/network/openvswitch/ovn_actions.go b/internal/server/network/openvswitch/ovn_actions.go index 5f7eff4a05f..6cecd973ae0 100644 --- a/internal/server/network/openvswitch/ovn_actions.go +++ b/internal/server/network/openvswitch/ovn_actions.go @@ -192,7 +192,7 @@ func (o *OVN) LogicalRouterAdd(routerName OVNRouter, mayExist bool) error { } // LogicalRouterDelete deletes a named logical router. -func (o OVN) LogicalRouterDelete(routerName OVNRouter) error { +func (o *OVN) LogicalRouterDelete(routerName OVNRouter) error { _, err := o.nbctl("--if-exists", "lr-del", string(routerName)) if err != nil { return err From e67cddf68fc9b3ee6bb574ae126a5ae0abc69ca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Mon, 18 Dec 2023 18:40:18 -0500 Subject: [PATCH 12/38] incusd/network/openvswitch: Port ChassisGroupChassisAdd to ovsdb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- .../server/network/openvswitch/ovn_actions.go | 77 ++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/internal/server/network/openvswitch/ovn_actions.go b/internal/server/network/openvswitch/ovn_actions.go index 6cecd973ae0..077dec3f36b 100644 --- a/internal/server/network/openvswitch/ovn_actions.go +++ b/internal/server/network/openvswitch/ovn_actions.go @@ -1,13 +1,17 @@ package openvswitch import ( + "context" "fmt" "net" "strconv" "strings" "time" + "github.com/ovn-org/libovsdb/ovsdb" + "github.com/lxc/incus/internal/iprange" + ovnNB "github.com/lxc/incus/internal/server/network/openvswitch/schema/ovn-nb" "github.com/lxc/incus/shared/util" ) @@ -1429,11 +1433,82 @@ func (o *OVN) ChassisGroupDelete(haChassisGroupName OVNChassisGroup) error { // ChassisGroupChassisAdd adds a chassis ID to an HA chassis group with the specified priority. func (o *OVN) ChassisGroupChassisAdd(haChassisGroupName OVNChassisGroup, chassisID string, priority uint) error { - _, err := o.nbctl("ha-chassis-group-add-chassis", string(haChassisGroupName), chassisID, fmt.Sprintf("%d", priority)) + // Get the client. + client, cleanup, err := o.client(ovnDatabaseNorthbound) + if err != nil { + return err + } + + defer cleanup() + + ctx := context.TODO() + operations := []ovsdb.Operation{} + + // Get the chassis group. + haGroup := &ovnNB.HAChassisGroup{Name: string(haChassisGroupName)} + err = client.Get(ctx, haGroup) if err != nil { return err } + // Look for the chassis in the group. + var haChassis *ovnNB.HAChassis + + for _, entry := range haGroup.HaChassis { + chassis := &ovnNB.HAChassis{UUID: entry} + err = client.Get(ctx, chassis) + if err != nil { + return err + } + + if chassis.ChassisName == chassisID { + haChassis = chassis + break + } + } + + if haChassis == nil { + // No entry found, add a new one. + haChassis = &ovnNB.HAChassis{ + UUID: "chassis", + ChassisName: chassisID, + Priority: int(priority), + } + + createOps, err := client.Create(haChassis) + if err != nil { + return err + } + + operations = append(operations, createOps...) + + // Add the HA Chassis to the group. + haGroup.HaChassis = append(haGroup.HaChassis, "chassis") + updateOps, err := client.Where(haGroup).Update(haGroup) + if err != nil { + return err + } + + operations = append(operations, updateOps...) + } else if haChassis.Priority != int(priority) { + // Found but wrong priority, correct it. + haChassis.Priority = int(priority) + updateOps, err := client.Where(haChassis).Update(haChassis) + if err != nil { + return err + } + + operations = append(operations, updateOps...) + } + + // Apply the changes. + if len(operations) > 0 { + _, err := client.Transact(ctx, operations...) + if err != nil { + return err + } + } + return nil } From ee3f282ecbef082d779bcafa846c577193629ae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Mon, 18 Dec 2023 20:01:56 -0500 Subject: [PATCH 13/38] incusd/server/network: Move ovn to separate package MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- .../server/network/{openvswitch => ovn}/ovn.go | 9 +++++---- .../network/{openvswitch => ovn}/ovn_actions.go | 4 ++-- .../{openvswitch => ovn}/schema/ovn-nb/acl.go | 0 .../schema/ovn-nb/address_set.go | 0 .../{openvswitch => ovn}/schema/ovn-nb/bfd.go | 0 .../schema/ovn-nb/chassis_template_var.go | 0 .../schema/ovn-nb/connection.go | 0 .../{openvswitch => ovn}/schema/ovn-nb/copp.go | 0 .../schema/ovn-nb/dhcp_options.go | 0 .../{openvswitch => ovn}/schema/ovn-nb/dns.go | 0 .../schema/ovn-nb/forwarding_group.go | 0 .../schema/ovn-nb/gateway_chassis.go | 0 .../schema/ovn-nb/ha_chassis.go | 0 .../schema/ovn-nb/ha_chassis_group.go | 0 .../schema/ovn-nb/load_balancer.go | 0 .../schema/ovn-nb/load_balancer_group.go | 0 .../schema/ovn-nb/load_balancer_health_check.go | 0 .../schema/ovn-nb/logical_router.go | 0 .../schema/ovn-nb/logical_router_policy.go | 0 .../schema/ovn-nb/logical_router_port.go | 0 .../schema/ovn-nb/logical_router_static_route.go | 0 .../schema/ovn-nb/logical_switch.go | 0 .../schema/ovn-nb/logical_switch_port.go | 0 .../{openvswitch => ovn}/schema/ovn-nb/meter.go | 0 .../schema/ovn-nb/meter_band.go | 0 .../{openvswitch => ovn}/schema/ovn-nb/mirror.go | 0 .../{openvswitch => ovn}/schema/ovn-nb/model.go | 0 .../{openvswitch => ovn}/schema/ovn-nb/nat.go | 0 .../schema/ovn-nb/nb_global.go | 0 .../schema/ovn-nb/port_group.go | 0 .../{openvswitch => ovn}/schema/ovn-nb/qos.go | 0 .../{openvswitch => ovn}/schema/ovn-nb/ssl.go | 0 .../schema/ovn-nb/static_mac_binding.go | 0 .../schema/ovn-sb/address_set.go | 0 .../{openvswitch => ovn}/schema/ovn-sb/bfd.go | 0 .../schema/ovn-sb/chassis.go | 0 .../schema/ovn-sb/chassis_private.go | 0 .../schema/ovn-sb/chassis_template_var.go | 0 .../schema/ovn-sb/connection.go | 0 .../schema/ovn-sb/controller_event.go | 0 .../schema/ovn-sb/datapath_binding.go | 0 .../schema/ovn-sb/dhcp_options.go | 0 .../schema/ovn-sb/dhcpv6_options.go | 0 .../{openvswitch => ovn}/schema/ovn-sb/dns.go | 0 .../{openvswitch => ovn}/schema/ovn-sb/encap.go | 0 .../{openvswitch => ovn}/schema/ovn-sb/fdb.go | 0 .../schema/ovn-sb/gateway_chassis.go | 0 .../schema/ovn-sb/ha_chassis.go | 0 .../schema/ovn-sb/ha_chassis_group.go | 0 .../schema/ovn-sb/igmp_group.go | 0 .../schema/ovn-sb/ip_multicast.go | 0 .../schema/ovn-sb/load_balancer.go | 0 .../schema/ovn-sb/logical_dp_group.go | 0 .../schema/ovn-sb/logical_flow.go | 0 .../schema/ovn-sb/mac_binding.go | 0 .../{openvswitch => ovn}/schema/ovn-sb/meter.go | 0 .../schema/ovn-sb/meter_band.go | 0 .../{openvswitch => ovn}/schema/ovn-sb/mirror.go | 0 .../{openvswitch => ovn}/schema/ovn-sb/model.go | 0 .../schema/ovn-sb/multicast_group.go | 0 .../schema/ovn-sb/port_binding.go | 0 .../schema/ovn-sb/port_group.go | 0 .../schema/ovn-sb/rbac_permission.go | 0 .../schema/ovn-sb/rbac_role.go | 0 .../schema/ovn-sb/sb_global.go | 0 .../schema/ovn-sb/service_monitor.go | 0 .../{openvswitch => ovn}/schema/ovn-sb/ssl.go | 0 .../schema/ovn-sb/static_mac_binding.go | 0 internal/server/network/ovn/shared.go | 16 ++++++++++++++++ 69 files changed, 23 insertions(+), 6 deletions(-) rename internal/server/network/{openvswitch => ovn}/ovn.go (96%) rename internal/server/network/{openvswitch => ovn}/ovn_actions.go (99%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/acl.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/address_set.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/bfd.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/chassis_template_var.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/connection.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/copp.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/dhcp_options.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/dns.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/forwarding_group.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/gateway_chassis.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/ha_chassis.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/ha_chassis_group.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/load_balancer.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/load_balancer_group.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/load_balancer_health_check.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/logical_router.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/logical_router_policy.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/logical_router_port.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/logical_router_static_route.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/logical_switch.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/logical_switch_port.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/meter.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/meter_band.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/mirror.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/model.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/nat.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/nb_global.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/port_group.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/qos.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/ssl.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-nb/static_mac_binding.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/address_set.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/bfd.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/chassis.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/chassis_private.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/chassis_template_var.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/connection.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/controller_event.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/datapath_binding.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/dhcp_options.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/dhcpv6_options.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/dns.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/encap.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/fdb.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/gateway_chassis.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/ha_chassis.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/ha_chassis_group.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/igmp_group.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/ip_multicast.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/load_balancer.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/logical_dp_group.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/logical_flow.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/mac_binding.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/meter.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/meter_band.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/mirror.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/model.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/multicast_group.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/port_binding.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/port_group.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/rbac_permission.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/rbac_role.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/sb_global.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/service_monitor.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/ssl.go (100%) rename internal/server/network/{openvswitch => ovn}/schema/ovn-sb/static_mac_binding.go (100%) create mode 100644 internal/server/network/ovn/shared.go diff --git a/internal/server/network/openvswitch/ovn.go b/internal/server/network/ovn/ovn.go similarity index 96% rename from internal/server/network/openvswitch/ovn.go rename to internal/server/network/ovn/ovn.go index 5106a06ea53..8087e7550cc 100644 --- a/internal/server/network/openvswitch/ovn.go +++ b/internal/server/network/ovn/ovn.go @@ -1,4 +1,4 @@ -package openvswitch +package ovn import ( "context" @@ -15,8 +15,9 @@ import ( ovsdbModel "github.com/ovn-org/libovsdb/model" "github.com/lxc/incus/internal/linux" - ovnNB "github.com/lxc/incus/internal/server/network/openvswitch/schema/ovn-nb" - ovnSB "github.com/lxc/incus/internal/server/network/openvswitch/schema/ovn-sb" + "github.com/lxc/incus/internal/server/network/openvswitch" + ovnNB "github.com/lxc/incus/internal/server/network/ovn/schema/ovn-nb" + ovnSB "github.com/lxc/incus/internal/server/network/ovn/schema/ovn-sb" "github.com/lxc/incus/internal/server/state" "github.com/lxc/incus/shared/subprocess" ) @@ -25,7 +26,7 @@ import ( func NewOVN(s *state.State) (*OVN, error) { // Get database connection strings. nbConnection := s.GlobalConfig.NetworkOVNNorthboundConnection() - sbConnection, err := NewOVS().OVNSouthboundDBRemoteAddress() + sbConnection, err := openvswitch.NewOVS().OVNSouthboundDBRemoteAddress() if err != nil { return nil, fmt.Errorf("Failed to get OVN southbound connection string: %w", err) } diff --git a/internal/server/network/openvswitch/ovn_actions.go b/internal/server/network/ovn/ovn_actions.go similarity index 99% rename from internal/server/network/openvswitch/ovn_actions.go rename to internal/server/network/ovn/ovn_actions.go index 077dec3f36b..4a9e6403881 100644 --- a/internal/server/network/openvswitch/ovn_actions.go +++ b/internal/server/network/ovn/ovn_actions.go @@ -1,4 +1,4 @@ -package openvswitch +package ovn import ( "context" @@ -11,7 +11,7 @@ import ( "github.com/ovn-org/libovsdb/ovsdb" "github.com/lxc/incus/internal/iprange" - ovnNB "github.com/lxc/incus/internal/server/network/openvswitch/schema/ovn-nb" + ovnNB "github.com/lxc/incus/internal/server/network/ovn/schema/ovn-nb" "github.com/lxc/incus/shared/util" ) diff --git a/internal/server/network/openvswitch/schema/ovn-nb/acl.go b/internal/server/network/ovn/schema/ovn-nb/acl.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/acl.go rename to internal/server/network/ovn/schema/ovn-nb/acl.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/address_set.go b/internal/server/network/ovn/schema/ovn-nb/address_set.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/address_set.go rename to internal/server/network/ovn/schema/ovn-nb/address_set.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/bfd.go b/internal/server/network/ovn/schema/ovn-nb/bfd.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/bfd.go rename to internal/server/network/ovn/schema/ovn-nb/bfd.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/chassis_template_var.go b/internal/server/network/ovn/schema/ovn-nb/chassis_template_var.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/chassis_template_var.go rename to internal/server/network/ovn/schema/ovn-nb/chassis_template_var.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/connection.go b/internal/server/network/ovn/schema/ovn-nb/connection.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/connection.go rename to internal/server/network/ovn/schema/ovn-nb/connection.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/copp.go b/internal/server/network/ovn/schema/ovn-nb/copp.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/copp.go rename to internal/server/network/ovn/schema/ovn-nb/copp.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/dhcp_options.go b/internal/server/network/ovn/schema/ovn-nb/dhcp_options.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/dhcp_options.go rename to internal/server/network/ovn/schema/ovn-nb/dhcp_options.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/dns.go b/internal/server/network/ovn/schema/ovn-nb/dns.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/dns.go rename to internal/server/network/ovn/schema/ovn-nb/dns.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/forwarding_group.go b/internal/server/network/ovn/schema/ovn-nb/forwarding_group.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/forwarding_group.go rename to internal/server/network/ovn/schema/ovn-nb/forwarding_group.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/gateway_chassis.go b/internal/server/network/ovn/schema/ovn-nb/gateway_chassis.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/gateway_chassis.go rename to internal/server/network/ovn/schema/ovn-nb/gateway_chassis.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/ha_chassis.go b/internal/server/network/ovn/schema/ovn-nb/ha_chassis.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/ha_chassis.go rename to internal/server/network/ovn/schema/ovn-nb/ha_chassis.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/ha_chassis_group.go b/internal/server/network/ovn/schema/ovn-nb/ha_chassis_group.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/ha_chassis_group.go rename to internal/server/network/ovn/schema/ovn-nb/ha_chassis_group.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/load_balancer.go b/internal/server/network/ovn/schema/ovn-nb/load_balancer.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/load_balancer.go rename to internal/server/network/ovn/schema/ovn-nb/load_balancer.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/load_balancer_group.go b/internal/server/network/ovn/schema/ovn-nb/load_balancer_group.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/load_balancer_group.go rename to internal/server/network/ovn/schema/ovn-nb/load_balancer_group.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/load_balancer_health_check.go b/internal/server/network/ovn/schema/ovn-nb/load_balancer_health_check.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/load_balancer_health_check.go rename to internal/server/network/ovn/schema/ovn-nb/load_balancer_health_check.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/logical_router.go b/internal/server/network/ovn/schema/ovn-nb/logical_router.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/logical_router.go rename to internal/server/network/ovn/schema/ovn-nb/logical_router.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/logical_router_policy.go b/internal/server/network/ovn/schema/ovn-nb/logical_router_policy.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/logical_router_policy.go rename to internal/server/network/ovn/schema/ovn-nb/logical_router_policy.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/logical_router_port.go b/internal/server/network/ovn/schema/ovn-nb/logical_router_port.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/logical_router_port.go rename to internal/server/network/ovn/schema/ovn-nb/logical_router_port.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/logical_router_static_route.go b/internal/server/network/ovn/schema/ovn-nb/logical_router_static_route.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/logical_router_static_route.go rename to internal/server/network/ovn/schema/ovn-nb/logical_router_static_route.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/logical_switch.go b/internal/server/network/ovn/schema/ovn-nb/logical_switch.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/logical_switch.go rename to internal/server/network/ovn/schema/ovn-nb/logical_switch.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/logical_switch_port.go b/internal/server/network/ovn/schema/ovn-nb/logical_switch_port.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/logical_switch_port.go rename to internal/server/network/ovn/schema/ovn-nb/logical_switch_port.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/meter.go b/internal/server/network/ovn/schema/ovn-nb/meter.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/meter.go rename to internal/server/network/ovn/schema/ovn-nb/meter.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/meter_band.go b/internal/server/network/ovn/schema/ovn-nb/meter_band.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/meter_band.go rename to internal/server/network/ovn/schema/ovn-nb/meter_band.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/mirror.go b/internal/server/network/ovn/schema/ovn-nb/mirror.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/mirror.go rename to internal/server/network/ovn/schema/ovn-nb/mirror.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/model.go b/internal/server/network/ovn/schema/ovn-nb/model.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/model.go rename to internal/server/network/ovn/schema/ovn-nb/model.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/nat.go b/internal/server/network/ovn/schema/ovn-nb/nat.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/nat.go rename to internal/server/network/ovn/schema/ovn-nb/nat.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/nb_global.go b/internal/server/network/ovn/schema/ovn-nb/nb_global.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/nb_global.go rename to internal/server/network/ovn/schema/ovn-nb/nb_global.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/port_group.go b/internal/server/network/ovn/schema/ovn-nb/port_group.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/port_group.go rename to internal/server/network/ovn/schema/ovn-nb/port_group.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/qos.go b/internal/server/network/ovn/schema/ovn-nb/qos.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/qos.go rename to internal/server/network/ovn/schema/ovn-nb/qos.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/ssl.go b/internal/server/network/ovn/schema/ovn-nb/ssl.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/ssl.go rename to internal/server/network/ovn/schema/ovn-nb/ssl.go diff --git a/internal/server/network/openvswitch/schema/ovn-nb/static_mac_binding.go b/internal/server/network/ovn/schema/ovn-nb/static_mac_binding.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-nb/static_mac_binding.go rename to internal/server/network/ovn/schema/ovn-nb/static_mac_binding.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/address_set.go b/internal/server/network/ovn/schema/ovn-sb/address_set.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/address_set.go rename to internal/server/network/ovn/schema/ovn-sb/address_set.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/bfd.go b/internal/server/network/ovn/schema/ovn-sb/bfd.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/bfd.go rename to internal/server/network/ovn/schema/ovn-sb/bfd.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/chassis.go b/internal/server/network/ovn/schema/ovn-sb/chassis.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/chassis.go rename to internal/server/network/ovn/schema/ovn-sb/chassis.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/chassis_private.go b/internal/server/network/ovn/schema/ovn-sb/chassis_private.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/chassis_private.go rename to internal/server/network/ovn/schema/ovn-sb/chassis_private.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/chassis_template_var.go b/internal/server/network/ovn/schema/ovn-sb/chassis_template_var.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/chassis_template_var.go rename to internal/server/network/ovn/schema/ovn-sb/chassis_template_var.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/connection.go b/internal/server/network/ovn/schema/ovn-sb/connection.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/connection.go rename to internal/server/network/ovn/schema/ovn-sb/connection.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/controller_event.go b/internal/server/network/ovn/schema/ovn-sb/controller_event.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/controller_event.go rename to internal/server/network/ovn/schema/ovn-sb/controller_event.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/datapath_binding.go b/internal/server/network/ovn/schema/ovn-sb/datapath_binding.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/datapath_binding.go rename to internal/server/network/ovn/schema/ovn-sb/datapath_binding.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/dhcp_options.go b/internal/server/network/ovn/schema/ovn-sb/dhcp_options.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/dhcp_options.go rename to internal/server/network/ovn/schema/ovn-sb/dhcp_options.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/dhcpv6_options.go b/internal/server/network/ovn/schema/ovn-sb/dhcpv6_options.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/dhcpv6_options.go rename to internal/server/network/ovn/schema/ovn-sb/dhcpv6_options.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/dns.go b/internal/server/network/ovn/schema/ovn-sb/dns.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/dns.go rename to internal/server/network/ovn/schema/ovn-sb/dns.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/encap.go b/internal/server/network/ovn/schema/ovn-sb/encap.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/encap.go rename to internal/server/network/ovn/schema/ovn-sb/encap.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/fdb.go b/internal/server/network/ovn/schema/ovn-sb/fdb.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/fdb.go rename to internal/server/network/ovn/schema/ovn-sb/fdb.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/gateway_chassis.go b/internal/server/network/ovn/schema/ovn-sb/gateway_chassis.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/gateway_chassis.go rename to internal/server/network/ovn/schema/ovn-sb/gateway_chassis.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/ha_chassis.go b/internal/server/network/ovn/schema/ovn-sb/ha_chassis.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/ha_chassis.go rename to internal/server/network/ovn/schema/ovn-sb/ha_chassis.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/ha_chassis_group.go b/internal/server/network/ovn/schema/ovn-sb/ha_chassis_group.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/ha_chassis_group.go rename to internal/server/network/ovn/schema/ovn-sb/ha_chassis_group.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/igmp_group.go b/internal/server/network/ovn/schema/ovn-sb/igmp_group.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/igmp_group.go rename to internal/server/network/ovn/schema/ovn-sb/igmp_group.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/ip_multicast.go b/internal/server/network/ovn/schema/ovn-sb/ip_multicast.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/ip_multicast.go rename to internal/server/network/ovn/schema/ovn-sb/ip_multicast.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/load_balancer.go b/internal/server/network/ovn/schema/ovn-sb/load_balancer.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/load_balancer.go rename to internal/server/network/ovn/schema/ovn-sb/load_balancer.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/logical_dp_group.go b/internal/server/network/ovn/schema/ovn-sb/logical_dp_group.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/logical_dp_group.go rename to internal/server/network/ovn/schema/ovn-sb/logical_dp_group.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/logical_flow.go b/internal/server/network/ovn/schema/ovn-sb/logical_flow.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/logical_flow.go rename to internal/server/network/ovn/schema/ovn-sb/logical_flow.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/mac_binding.go b/internal/server/network/ovn/schema/ovn-sb/mac_binding.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/mac_binding.go rename to internal/server/network/ovn/schema/ovn-sb/mac_binding.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/meter.go b/internal/server/network/ovn/schema/ovn-sb/meter.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/meter.go rename to internal/server/network/ovn/schema/ovn-sb/meter.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/meter_band.go b/internal/server/network/ovn/schema/ovn-sb/meter_band.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/meter_band.go rename to internal/server/network/ovn/schema/ovn-sb/meter_band.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/mirror.go b/internal/server/network/ovn/schema/ovn-sb/mirror.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/mirror.go rename to internal/server/network/ovn/schema/ovn-sb/mirror.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/model.go b/internal/server/network/ovn/schema/ovn-sb/model.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/model.go rename to internal/server/network/ovn/schema/ovn-sb/model.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/multicast_group.go b/internal/server/network/ovn/schema/ovn-sb/multicast_group.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/multicast_group.go rename to internal/server/network/ovn/schema/ovn-sb/multicast_group.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/port_binding.go b/internal/server/network/ovn/schema/ovn-sb/port_binding.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/port_binding.go rename to internal/server/network/ovn/schema/ovn-sb/port_binding.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/port_group.go b/internal/server/network/ovn/schema/ovn-sb/port_group.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/port_group.go rename to internal/server/network/ovn/schema/ovn-sb/port_group.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/rbac_permission.go b/internal/server/network/ovn/schema/ovn-sb/rbac_permission.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/rbac_permission.go rename to internal/server/network/ovn/schema/ovn-sb/rbac_permission.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/rbac_role.go b/internal/server/network/ovn/schema/ovn-sb/rbac_role.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/rbac_role.go rename to internal/server/network/ovn/schema/ovn-sb/rbac_role.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/sb_global.go b/internal/server/network/ovn/schema/ovn-sb/sb_global.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/sb_global.go rename to internal/server/network/ovn/schema/ovn-sb/sb_global.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/service_monitor.go b/internal/server/network/ovn/schema/ovn-sb/service_monitor.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/service_monitor.go rename to internal/server/network/ovn/schema/ovn-sb/service_monitor.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/ssl.go b/internal/server/network/ovn/schema/ovn-sb/ssl.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/ssl.go rename to internal/server/network/ovn/schema/ovn-sb/ssl.go diff --git a/internal/server/network/openvswitch/schema/ovn-sb/static_mac_binding.go b/internal/server/network/ovn/schema/ovn-sb/static_mac_binding.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovn-sb/static_mac_binding.go rename to internal/server/network/ovn/schema/ovn-sb/static_mac_binding.go diff --git a/internal/server/network/ovn/shared.go b/internal/server/network/ovn/shared.go new file mode 100644 index 00000000000..58b6fc0bde2 --- /dev/null +++ b/internal/server/network/ovn/shared.go @@ -0,0 +1,16 @@ +package ovn + +import ( + "strconv" + "strings" +) + +// unquote passes s through strconv.Unquote if the first character is a ", otherwise returns s unmodified. +// This is useful as openvswitch's tools can sometimes return values double quoted if they start with a number. +func unquote(s string) (string, error) { + if strings.HasPrefix(s, `"`) { + return strconv.Unquote(s) + } + + return s, nil +} From 0b9a4cda51353f64ef5628f3cc63462fa47098f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Mon, 18 Dec 2023 20:03:33 -0500 Subject: [PATCH 14/38] Makefile: Update for new OVN package MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- Makefile | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 709f9c25c6c..5a155ae2cab 100644 --- a/Makefile +++ b/Makefile @@ -111,16 +111,21 @@ endif .PHONY: update-ovsdb update-ovsdb: go install github.com/ovn-org/libovsdb/cmd/modelgen@main + rm -Rf internal/server/network/openvswitch/schema mkdir internal/server/network/openvswitch/schema - curl -s https://raw.githubusercontent.com/ovn-org/ovn/v$(OVN_MINVER)/ovn-nb.ovsschema -o internal/server/network/openvswitch/schema/ovn-nb.json - curl -s https://raw.githubusercontent.com/ovn-org/ovn/v$(OVN_MINVER)/ovn-sb.ovsschema -o internal/server/network/openvswitch/schema/ovn-sb.json curl -s https://raw.githubusercontent.com/openvswitch/ovs/v$(OVS_MINVER)/vswitchd/vswitch.ovsschema -o internal/server/network/openvswitch/schema/ovs.json - modelgen -o internal/server/network/openvswitch/schema/ovn-nb internal/server/network/openvswitch/schema/ovn-nb.json - modelgen -o internal/server/network/openvswitch/schema/ovn-sb internal/server/network/openvswitch/schema/ovn-sb.json modelgen -o internal/server/network/openvswitch/schema/ovs internal/server/network/openvswitch/schema/ovs.json rm internal/server/network/openvswitch/schema/*.json + rm -Rf internal/server/network/ovn/schema + mkdir internal/server/network/ovn/schema + curl -s https://raw.githubusercontent.com/ovn-org/ovn/v$(OVN_MINVER)/ovn-nb.ovsschema -o internal/server/network/ovn/schema/ovn-nb.json + curl -s https://raw.githubusercontent.com/ovn-org/ovn/v$(OVN_MINVER)/ovn-sb.ovsschema -o internal/server/network/ovn/schema/ovn-sb.json + modelgen -o internal/server/network/ovn/schema/ovn-nb internal/server/network/ovn/schema/ovn-nb.json + modelgen -o internal/server/network/ovn/schema/ovn-sb internal/server/network/ovn/schema/ovn-sb.json + rm internal/server/network/ovn/schema/*.json + .PHONY: update-protobuf update-protobuf: protoc --go_out=. ./internal/migration/migrate.proto From d3f58844f6231e60416de833b9f8d51261290336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Mon, 18 Dec 2023 22:53:25 -0500 Subject: [PATCH 15/38] incusd/network/openvswitch: Update for separate ovn package MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- internal/server/network/openvswitch/ovs.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/server/network/openvswitch/ovs.go b/internal/server/network/openvswitch/ovs.go index ce2107ea6bc..80b37f26f60 100644 --- a/internal/server/network/openvswitch/ovs.go +++ b/internal/server/network/openvswitch/ovs.go @@ -137,7 +137,7 @@ func (o *OVS) BridgePortSet(portName string, options ...string) error { // InterfaceAssociateOVNSwitchPort removes any existing OVS ports associated to the specified ovnSwitchPortName // and then associates the specified interfaceName to the OVN switch port. -func (o *OVS) InterfaceAssociateOVNSwitchPort(interfaceName string, ovnSwitchPortName OVNSwitchPort) error { +func (o *OVS) InterfaceAssociateOVNSwitchPort(interfaceName string, ovnSwitchPortName string) error { // Clear existing ports that were formerly associated to ovnSwitchPortName. existingPorts, err := subprocess.RunCommand("ovs-vsctl", "--format=csv", "--no-headings", "--data=bare", "--colum=name", "find", "interface", fmt.Sprintf("external-ids:iface-id=%s", string(ovnSwitchPortName))) if err != nil { @@ -169,13 +169,13 @@ func (o *OVS) InterfaceAssociateOVNSwitchPort(interfaceName string, ovnSwitchPor } // InterfaceAssociatedOVNSwitchPort returns the OVN switch port associated to the OVS interface. -func (o *OVS) InterfaceAssociatedOVNSwitchPort(interfaceName string) (OVNSwitchPort, error) { +func (o *OVS) InterfaceAssociatedOVNSwitchPort(interfaceName string) (string, error) { ovnSwitchPort, err := subprocess.RunCommand("ovs-vsctl", "get", "interface", interfaceName, "external_ids:iface-id") if err != nil { return "", err } - return OVNSwitchPort(strings.TrimSpace(ovnSwitchPort)), nil + return strings.TrimSpace(ovnSwitchPort), nil } // ChassisID returns the local chassis ID. From e761dfbe24adb2a66c3cd2da0e315d2bb002ce32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Mon, 18 Dec 2023 22:55:30 -0500 Subject: [PATCH 16/38] incusd/network/openvswitch: Move TCP flags to ovn package MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- internal/server/network/openvswitch/ovs.go | 13 ------------- internal/server/network/ovn/const.go | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 13 deletions(-) create mode 100644 internal/server/network/ovn/const.go diff --git a/internal/server/network/openvswitch/ovs.go b/internal/server/network/openvswitch/ovs.go index 80b37f26f60..d12515923c9 100644 --- a/internal/server/network/openvswitch/ovs.go +++ b/internal/server/network/openvswitch/ovs.go @@ -14,19 +14,6 @@ import ( // ovnBridgeMappingMutex locks access to read/write external-ids:ovn-bridge-mappings. var ovnBridgeMappingMutex sync.Mutex -// OVS TCP Flags from OVS lib/packets.h. -const ( - TCPFIN = 0x001 - TCPSYN = 0x002 - TCPRST = 0x004 - TCPPSH = 0x008 - TCPACK = 0x010 - TCPURG = 0x020 - TCPECE = 0x040 - TCPCWR = 0x080 - TCPNS = 0x100 -) - // NewOVS initialises new OVS wrapper. func NewOVS() *OVS { return &OVS{} diff --git a/internal/server/network/ovn/const.go b/internal/server/network/ovn/const.go new file mode 100644 index 00000000000..690cace0776 --- /dev/null +++ b/internal/server/network/ovn/const.go @@ -0,0 +1,14 @@ +package ovn + +// OVS TCP Flags from OVS lib/packets.h. +const ( + TCPFIN = 0x001 + TCPSYN = 0x002 + TCPRST = 0x004 + TCPPSH = 0x008 + TCPACK = 0x010 + TCPURG = 0x020 + TCPECE = 0x040 + TCPCWR = 0x080 + TCPNS = 0x100 +) From a863460224f8f116262648ad9980ca820a8a4fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Mon, 18 Dec 2023 23:02:51 -0500 Subject: [PATCH 17/38] incusd: Update for network/ovn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- internal/server/device/nic_ovn.go | 19 +- internal/server/network/acl/acl_ovn.go | 80 ++++---- internal/server/network/acl/driver_common.go | 4 +- internal/server/network/driver_ovn.go | 193 ++++++++++--------- 4 files changed, 149 insertions(+), 147 deletions(-) diff --git a/internal/server/device/nic_ovn.go b/internal/server/device/nic_ovn.go index 8dcc46c9da3..b2e152a60a4 100644 --- a/internal/server/device/nic_ovn.go +++ b/internal/server/device/nic_ovn.go @@ -23,6 +23,7 @@ import ( "github.com/lxc/incus/internal/server/network" "github.com/lxc/incus/internal/server/network/acl" "github.com/lxc/incus/internal/server/network/openvswitch" + "github.com/lxc/incus/internal/server/network/ovn" "github.com/lxc/incus/internal/server/project" "github.com/lxc/incus/internal/server/resources" localUtil "github.com/lxc/incus/internal/server/util" @@ -37,8 +38,8 @@ type ovnNet interface { InstanceDevicePortValidateExternalRoutes(deviceInstance instance.Instance, deviceName string, externalRoutes []*net.IPNet) error InstanceDevicePortAdd(instanceUUID string, deviceName string, deviceConfig deviceConfig.Device) error - InstanceDevicePortStart(opts *network.OVNInstanceNICSetupOpts, securityACLsRemove []string) (openvswitch.OVNSwitchPort, []net.IP, error) - InstanceDevicePortStop(ovsExternalOVNPort openvswitch.OVNSwitchPort, opts *network.OVNInstanceNICStopOpts) error + InstanceDevicePortStart(opts *network.OVNInstanceNICSetupOpts, securityACLsRemove []string) (ovn.OVNSwitchPort, []net.IP, error) + InstanceDevicePortStop(ovsExternalOVNPort ovn.OVNSwitchPort, opts *network.OVNInstanceNICStopOpts) error InstanceDevicePortRemove(instanceUUID string, deviceName string, deviceConfig deviceConfig.Device) error InstanceDevicePortIPs(instanceUUID string, deviceName string) ([]net.IP, error) } @@ -614,7 +615,7 @@ func (d *nicOVN) Start() (*deviceConfig.RunConfig, error) { return nil, fmt.Errorf("Failed getting OVS Chassis ID: %w", err) } - ovnClient, err := openvswitch.NewOVN(d.state) + ovnClient, err := ovn.NewOVN(d.state) if err != nil { return nil, fmt.Errorf("Failed to get OVN client: %w", err) } @@ -757,7 +758,7 @@ func (d *nicOVN) Update(oldDevices deviceConfig.Devices, isRunning bool) error { } if len(removedACLs) > 0 { - client, err := openvswitch.NewOVN(d.state) + client, err := ovn.NewOVN(d.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -825,7 +826,7 @@ func (d *nicOVN) Stop() (*deviceConfig.RunConfig, error) { // instance ports generated under an older regime to be cleaned up properly. networkVethFillFromVolatile(d.config, v) ovs := openvswitch.NewOVS() - var ovsExternalOVNPort openvswitch.OVNSwitchPort + var ovsExternalOVNPort string if d.config["nested"] == "" { ovsExternalOVNPort, err = ovs.InterfaceAssociatedOVNSwitchPort(d.config["host_name"]) if err != nil { @@ -857,7 +858,7 @@ func (d *nicOVN) Stop() (*deviceConfig.RunConfig, error) { } instanceUUID := d.inst.LocalConfig()["volatile.uuid"] - err = d.network.InstanceDevicePortStop(ovsExternalOVNPort, &network.OVNInstanceNICStopOpts{ + err = d.network.InstanceDevicePortStop(ovn.OVNSwitchPort(ovsExternalOVNPort), &network.OVNInstanceNICStopOpts{ InstanceUUID: instanceUUID, DeviceName: d.name, DeviceConfig: d.config, @@ -961,7 +962,7 @@ func (d *nicOVN) Remove() error { // Check for port groups that will become unused (and need deleting) as this NIC is deleted. securityACLs := util.SplitNTrimSpace(d.config["security.acls"], ",", -1, true) if len(securityACLs) > 0 { - client, err := openvswitch.NewOVN(d.state) + client, err := ovn.NewOVN(d.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -1106,7 +1107,7 @@ func (d *nicOVN) Register() error { return nil } -func (d *nicOVN) setupHostNIC(hostName string, ovnPortName openvswitch.OVNSwitchPort, uplink *api.Network) (revert.Hook, error) { +func (d *nicOVN) setupHostNIC(hostName string, ovnPortName ovn.OVNSwitchPort, uplink *api.Network) (revert.Hook, error) { revert := revert.New() defer revert.Fail() @@ -1135,7 +1136,7 @@ func (d *nicOVN) setupHostNIC(hostName string, ovnPortName openvswitch.OVNSwitch revert.Add(func() { _ = ovs.BridgePortDelete(integrationBridge, hostName) }) // Link OVS port to OVN logical port. - err = ovs.InterfaceAssociateOVNSwitchPort(hostName, ovnPortName) + err = ovs.InterfaceAssociateOVNSwitchPort(hostName, string(ovnPortName)) if err != nil { return nil, err } diff --git a/internal/server/network/acl/acl_ovn.go b/internal/server/network/acl/acl_ovn.go index 45c483f4f19..50204e8c47c 100644 --- a/internal/server/network/acl/acl_ovn.go +++ b/internal/server/network/acl/acl_ovn.go @@ -12,7 +12,7 @@ import ( "github.com/lxc/incus/internal/server/db" "github.com/lxc/incus/internal/server/db/cluster" "github.com/lxc/incus/internal/server/instance" - "github.com/lxc/incus/internal/server/network/openvswitch" + "github.com/lxc/incus/internal/server/network/ovn" "github.com/lxc/incus/internal/server/state" "github.com/lxc/incus/shared/api" "github.com/lxc/incus/shared/logger" @@ -36,27 +36,27 @@ const ovnACLPriorityPortGroupDrop = 500 const ovnACLPortGroupPrefix = "incus_acl" // OVNACLPortGroupName returns the port group name for a Network ACL ID. -func OVNACLPortGroupName(networkACLID int64) openvswitch.OVNPortGroup { +func OVNACLPortGroupName(networkACLID int64) ovn.OVNPortGroup { // OVN doesn't match port groups that have a "-" in them. So use an "_" for the separator. // This is because OVN port group names must match: [a-zA-Z_.][a-zA-Z_.0-9]*. - return openvswitch.OVNPortGroup(fmt.Sprintf("%s%d", ovnACLPortGroupPrefix, networkACLID)) + return ovn.OVNPortGroup(fmt.Sprintf("%s%d", ovnACLPortGroupPrefix, networkACLID)) } // OVNACLNetworkPortGroupName returns the port group name for a Network ACL ID and Network ID. -func OVNACLNetworkPortGroupName(networkACLID int64, networkID int64) openvswitch.OVNPortGroup { +func OVNACLNetworkPortGroupName(networkACLID int64, networkID int64) ovn.OVNPortGroup { // OVN doesn't match port groups that have a "-" in them. So use an "_" for the separator. // This is because OVN port group names must match: [a-zA-Z_.][a-zA-Z_.0-9]*. - return openvswitch.OVNPortGroup(fmt.Sprintf("%s%d_net%d", ovnACLPortGroupPrefix, networkACLID, networkID)) + return ovn.OVNPortGroup(fmt.Sprintf("%s%d_net%d", ovnACLPortGroupPrefix, networkACLID, networkID)) } // OVNIntSwitchPortGroupName returns the port group name for a Network ID. -func OVNIntSwitchPortGroupName(networkID int64) openvswitch.OVNPortGroup { - return openvswitch.OVNPortGroup(fmt.Sprintf("incus_net%d", networkID)) +func OVNIntSwitchPortGroupName(networkID int64) ovn.OVNPortGroup { + return ovn.OVNPortGroup(fmt.Sprintf("incus_net%d", networkID)) } // OVNIntSwitchPortGroupAddressSetPrefix returns the internal switch routes address set prefix for a Network ID. -func OVNIntSwitchPortGroupAddressSetPrefix(networkID int64) openvswitch.OVNAddressSet { - return openvswitch.OVNAddressSet(fmt.Sprintf("%s_routes", OVNIntSwitchPortGroupName(networkID))) +func OVNIntSwitchPortGroupAddressSetPrefix(networkID int64) ovn.OVNAddressSet { + return ovn.OVNAddressSet(fmt.Sprintf("%s_routes", OVNIntSwitchPortGroupName(networkID))) } // OVNNetworkPrefix returns the prefix used for OVN entities related to a Network ID. @@ -65,13 +65,13 @@ func OVNNetworkPrefix(networkID int64) string { } // OVNIntSwitchName returns the internal logical switch name for a Network ID. -func OVNIntSwitchName(networkID int64) openvswitch.OVNSwitch { - return openvswitch.OVNSwitch(fmt.Sprintf("%s-ls-int", OVNNetworkPrefix(networkID))) +func OVNIntSwitchName(networkID int64) ovn.OVNSwitch { + return ovn.OVNSwitch(fmt.Sprintf("%s-ls-int", OVNNetworkPrefix(networkID))) } // OVNIntSwitchRouterPortName returns OVN logical internal switch router port name. -func OVNIntSwitchRouterPortName(networkID int64) openvswitch.OVNSwitchPort { - return openvswitch.OVNSwitchPort(fmt.Sprintf("%s-lsp-router", OVNIntSwitchName(networkID))) +func OVNIntSwitchRouterPortName(networkID int64) ovn.OVNSwitchPort { + return ovn.OVNSwitchPort(fmt.Sprintf("%s-lsp-router", OVNIntSwitchName(networkID))) } // OVNEnsureACLs ensures that the requested aclNames exist as OVN port groups (creates & applies ACL rules if not), @@ -81,7 +81,7 @@ func OVNIntSwitchRouterPortName(networkID int64) openvswitch.OVNSwitchPort { // of the database and applied. For each network provided in aclNets, the network specific port group for each ACL // is checked for existence (it is created & applies network specific ACL rules if not). // Returns a revert fail function that can be used to undo this function if a subsequent step fails. -func OVNEnsureACLs(s *state.State, l logger.Logger, client *openvswitch.OVN, aclProjectName string, aclNameIDs map[string]int64, aclNets map[string]NetworkACLUsage, aclNames []string, reapplyRules bool) (revert.Hook, error) { +func OVNEnsureACLs(s *state.State, l logger.Logger, client *ovn.OVN, aclProjectName string, aclNameIDs map[string]int64, aclNets map[string]NetworkACLUsage, aclNames []string, reapplyRules bool) (revert.Hook, error) { revert := revert.New() defer revert.Fail() @@ -115,7 +115,7 @@ func OVNEnsureACLs(s *state.State, l logger.Logger, client *openvswitch.OVN, acl // Next check which OVN port groups need creating and which exist already. type aclStatus struct { name string - uuid openvswitch.OVNPortGroupUUID + uuid ovn.OVNPortGroupUUID aclInfo *api.NetworkACL addACLNets map[string]NetworkACLUsage } @@ -323,10 +323,10 @@ func ovnAddReferencedACLs(info *api.NetworkACL, referencedACLNames map[string]st } // ovnApplyToPortGroup applies the rules in the specified ACL to the specified port group. -func ovnApplyToPortGroup(l logger.Logger, client *openvswitch.OVN, aclInfo *api.NetworkACL, portGroupName openvswitch.OVNPortGroup, aclNameIDs map[string]int64, aclNets map[string]NetworkACLUsage, peerTargetNetIDs map[db.NetworkPeer]int64) error { +func ovnApplyToPortGroup(l logger.Logger, client *ovn.OVN, aclInfo *api.NetworkACL, portGroupName ovn.OVNPortGroup, aclNameIDs map[string]int64, aclNets map[string]NetworkACLUsage, peerTargetNetIDs map[db.NetworkPeer]int64) error { // Create slice for port group rules that has the capacity for ingress and egress rules, plus default rule. - portGroupRules := make([]openvswitch.OVNACLRule, 0, len(aclInfo.Ingress)+len(aclInfo.Egress)+1) - networkRules := make([]openvswitch.OVNACLRule, 0) + portGroupRules := make([]ovn.OVNACLRule, 0, len(aclInfo.Ingress)+len(aclInfo.Egress)+1) + networkRules := make([]ovn.OVNACLRule, 0) networkPeersNeeded := make([]db.NetworkPeer, 0) // convertACLRules converts the ACL rules to OVN ACL rules. @@ -373,7 +373,7 @@ func ovnApplyToPortGroup(l logger.Logger, client *openvswitch.OVN, aclInfo *api. defaultAction := "drop" defaultLogged := false - portGroupRules = append(portGroupRules, openvswitch.OVNACLRule{ + portGroupRules = append(portGroupRules, ovn.OVNACLRule{ Direction: "to-lport", // Always use this so that outport is available to Match. Action: defaultAction, Priority: ovnACLPriorityPortGroupDefaultAction, // Lowest priority to catch only unmatched traffic. @@ -419,10 +419,10 @@ func ovnApplyToPortGroup(l logger.Logger, client *openvswitch.OVN, aclInfo *api. // ovnRuleCriteriaToOVNACLRule converts an ACL rule into an OVNACLRule for an OVN port group or network. // Returns a bool indicating if any of the rule subjects are network specific. -func ovnRuleCriteriaToOVNACLRule(direction string, rule *api.NetworkACLRule, portGroupName openvswitch.OVNPortGroup, aclNameIDs map[string]int64, peerTargetNetIDs map[db.NetworkPeer]int64) (openvswitch.OVNACLRule, bool, []db.NetworkPeer, error) { +func ovnRuleCriteriaToOVNACLRule(direction string, rule *api.NetworkACLRule, portGroupName ovn.OVNPortGroup, aclNameIDs map[string]int64, peerTargetNetIDs map[db.NetworkPeer]int64) (ovn.OVNACLRule, bool, []db.NetworkPeer, error) { networkSpecific := false networkPeersNeeded := make([]db.NetworkPeer, 0) - portGroupRule := openvswitch.OVNACLRule{ + portGroupRule := ovn.OVNACLRule{ Direction: "to-lport", // Always use this so that outport is available to Match. } @@ -455,7 +455,7 @@ func ovnRuleCriteriaToOVNACLRule(direction string, rule *api.NetworkACLRule, por if rule.Source != "" { match, netSpecificMatch, networkPeers, err := ovnRuleSubjectToOVNACLMatch("src", aclNameIDs, peerTargetNetIDs, util.SplitNTrimSpace(rule.Source, ",", -1, false)...) if err != nil { - return openvswitch.OVNACLRule{}, false, nil, err + return ovn.OVNACLRule{}, false, nil, err } if netSpecificMatch { @@ -469,7 +469,7 @@ func ovnRuleCriteriaToOVNACLRule(direction string, rule *api.NetworkACLRule, por if rule.Destination != "" { match, netSpecificMatch, networkPeers, err := ovnRuleSubjectToOVNACLMatch("dst", aclNameIDs, peerTargetNetIDs, util.SplitNTrimSpace(rule.Destination, ",", -1, false)...) if err != nil { - return openvswitch.OVNACLRule{}, false, nil, err + return ovn.OVNACLRule{}, false, nil, err } if netSpecificMatch { @@ -566,18 +566,18 @@ func ovnRuleSubjectToOVNACLMatch(direction string, aclNameIDs map[string]int64, fieldParts = append(fieldParts, fmt.Sprintf("%s.%s == %s", protocol, direction, subjectCriterion)) } else { // If not valid IP subnet, check if subject is ACL name or network peer name. - var subjectPortSelector openvswitch.OVNPortGroup + var subjectPortSelector ovn.OVNPortGroup if util.ValueInSlice(subjectCriterion, ruleSubjectInternalAliases) { // Use pseudo port group name for special reserved port selector types. // These will be expanded later for each network specific rule. // Convert deprecated #internal to non-deprecated @internal if needed. - subjectPortSelector = openvswitch.OVNPortGroup(ruleSubjectInternal) + subjectPortSelector = ovn.OVNPortGroup(ruleSubjectInternal) networkSpecific = true } else if util.ValueInSlice(subjectCriterion, ruleSubjectExternalAliases) { // Use pseudo port group name for special reserved port selector types. // These will be expanded later for each network specific rule. // Convert deprecated #external to non-deprecated @external if needed. - subjectPortSelector = openvswitch.OVNPortGroup(ruleSubjectExternal) + subjectPortSelector = ovn.OVNPortGroup(ruleSubjectExternal) networkSpecific = true } else if strings.HasPrefix(subjectCriterion, "@") { // Subject is a network peer name. Convert to address set criteria. @@ -626,8 +626,8 @@ func ovnRuleSubjectToOVNACLMatch(direction string, aclNameIDs map[string]int64, } // OVNApplyNetworkBaselineRules applies preset baseline logical switch rules to a allow access to network services. -func OVNApplyNetworkBaselineRules(client *openvswitch.OVN, switchName openvswitch.OVNSwitch, routerPortName openvswitch.OVNSwitchPort, intRouterIPs []*net.IPNet, dnsIPs []net.IP) error { - rules := []openvswitch.OVNACLRule{ +func OVNApplyNetworkBaselineRules(client *ovn.OVN, switchName ovn.OVNSwitch, routerPortName ovn.OVNSwitchPort, intRouterIPs []*net.IPNet, dnsIPs []net.IP) error { + rules := []ovn.OVNACLRule{ { Direction: "to-lport", Action: "allow", @@ -684,7 +684,7 @@ func OVNApplyNetworkBaselineRules(client *openvswitch.OVN, switchName openvswitc Direction: "to-lport", Action: "allow", Priority: ovnACLPrioritySwitchAllow, - Match: fmt.Sprintf("tcp && tcp.flags == %#.03x", openvswitch.TCPRST|openvswitch.TCPACK), // TCP RST|ACK messages for ACL reject. + Match: fmt.Sprintf("tcp && tcp.flags == %#.03x", ovn.TCPRST|ovn.TCPACK), // TCP RST|ACK messages for ACL reject. }, } @@ -700,13 +700,13 @@ func OVNApplyNetworkBaselineRules(client *openvswitch.OVN, switchName openvswitc } rules = append(rules, - openvswitch.OVNACLRule{ + ovn.OVNACLRule{ Direction: "to-lport", Action: "allow", Priority: ovnACLPrioritySwitchAllow, Match: fmt.Sprintf(`outport == "%s" && icmp%d.type == %d && ip%d.dst == %s`, routerPortName, ipVersion, icmpPingType, ipVersion, intRouterIP.IP), }, - openvswitch.OVNACLRule{ + ovn.OVNACLRule{ Direction: "to-lport", Action: "allow", Priority: ovnACLPrioritySwitchAllow, @@ -723,7 +723,7 @@ func OVNApplyNetworkBaselineRules(client *openvswitch.OVN, switchName openvswitc } rules = append(rules, - openvswitch.OVNACLRule{ + ovn.OVNACLRule{ Direction: "to-lport", Action: "allow", Priority: ovnACLPrioritySwitchAllow, @@ -746,7 +746,7 @@ func OVNApplyNetworkBaselineRules(client *openvswitch.OVN, switchName openvswitc // The combination of ignoring the specifified usage type and explicit keep ACLs allows the caller to ensure that // the desired ACLs are considered unused by the usage type even if the referring config has not yet been removed // from the database. -func OVNPortGroupDeleteIfUnused(s *state.State, l logger.Logger, client *openvswitch.OVN, aclProjectName string, ignoreUsageType any, ignoreUsageNicName string, keepACLs ...string) error { +func OVNPortGroupDeleteIfUnused(s *state.State, l logger.Logger, client *ovn.OVN, aclProjectName string, ignoreUsageType any, ignoreUsageNicName string, keepACLs ...string) error { // Get map of ACL names to DB IDs (used for generating OVN port group names). aclNameIDs, err := s.DB.Cluster.GetNetworkACLIDsByNames(aclProjectName) if err != nil { @@ -777,7 +777,7 @@ func OVNPortGroupDeleteIfUnused(s *state.State, l logger.Logger, client *openvsw // hasKeeperPrefix indicates if the port group provided matches the prefix of one of the keepACLs. // This will include ACL network port groups too. - hasKeeperPrefix := func(portGroup openvswitch.OVNPortGroup) bool { + hasKeeperPrefix := func(portGroup ovn.OVNPortGroup) bool { for _, keepACLName := range keepACLs { keepACLPortGroup := OVNACLPortGroupName(aclNameIDs[keepACLName]) if strings.HasPrefix(string(portGroup), string(keepACLPortGroup)) { @@ -790,7 +790,7 @@ func OVNPortGroupDeleteIfUnused(s *state.State, l logger.Logger, client *openvsw // Filter project port group list by ACL related ones, and store them in a map keyed by port group name. // This contains the initial candidates for removal. But any found to be in use will be removed from list. - removeACLPortGroups := make(map[openvswitch.OVNPortGroup]struct{}, 0) + removeACLPortGroups := make(map[ovn.OVNPortGroup]struct{}, 0) for _, portGroup := range portGroups { // If port group is related to an ACL and is not related to one of keepACLs, then add it as a // candidate for removal. @@ -944,7 +944,7 @@ func OVNPortGroupDeleteIfUnused(s *state.State, l logger.Logger, client *openvsw } // Now remove any remaining port groups left in removeACLPortGroups. - removePortGroups := make([]openvswitch.OVNPortGroup, 0, len(removeACLPortGroups)) + removePortGroups := make([]ovn.OVNPortGroup, 0, len(removeACLPortGroups)) for removeACLPortGroup := range removeACLPortGroups { removePortGroups = append(removePortGroups, removeACLPortGroup) l.Debug("Scheduled deletion of unused ACL OVN port group", logger.Ctx{"portGroup": removeACLPortGroup}) @@ -961,11 +961,11 @@ func OVNPortGroupDeleteIfUnused(s *state.State, l logger.Logger, client *openvsw } // OVNPortGroupInstanceNICSchedule adds the specified NIC port to the specified port groups in the changeSet. -func OVNPortGroupInstanceNICSchedule(portUUID openvswitch.OVNSwitchPortUUID, changeSet map[openvswitch.OVNPortGroup][]openvswitch.OVNSwitchPortUUID, portGroups ...openvswitch.OVNPortGroup) { +func OVNPortGroupInstanceNICSchedule(portUUID ovn.OVNSwitchPortUUID, changeSet map[ovn.OVNPortGroup][]ovn.OVNSwitchPortUUID, portGroups ...ovn.OVNPortGroup) { for _, portGroupName := range portGroups { _, found := changeSet[portGroupName] if !found { - changeSet[portGroupName] = []openvswitch.OVNSwitchPortUUID{} + changeSet[portGroupName] = []ovn.OVNSwitchPortUUID{} } changeSet[portGroupName] = append(changeSet[portGroupName], portUUID) @@ -973,7 +973,7 @@ func OVNPortGroupInstanceNICSchedule(portUUID openvswitch.OVNSwitchPortUUID, cha } // OVNApplyInstanceNICDefaultRules applies instance NIC default rules to per-network port group. -func OVNApplyInstanceNICDefaultRules(client *openvswitch.OVN, switchPortGroup openvswitch.OVNPortGroup, logPrefix string, nicPortName openvswitch.OVNSwitchPort, ingressAction string, ingressLogged bool, egressAction string, egressLogged bool) error { +func OVNApplyInstanceNICDefaultRules(client *ovn.OVN, switchPortGroup ovn.OVNPortGroup, logPrefix string, nicPortName ovn.OVNSwitchPort, ingressAction string, ingressLogged bool, egressAction string, egressLogged bool) error { if !util.ValueInSlice(ingressAction, ValidActions) { return fmt.Errorf("Invalid ingress action %q", ingressAction) } @@ -982,7 +982,7 @@ func OVNApplyInstanceNICDefaultRules(client *openvswitch.OVN, switchPortGroup op return fmt.Errorf("Invalid egress action %q", egressAction) } - rules := []openvswitch.OVNACLRule{ + rules := []ovn.OVNACLRule{ { Direction: "to-lport", Action: egressAction, diff --git a/internal/server/network/acl/driver_common.go b/internal/server/network/acl/driver_common.go index ce3bee36b06..85b808080c3 100644 --- a/internal/server/network/acl/driver_common.go +++ b/internal/server/network/acl/driver_common.go @@ -16,7 +16,7 @@ import ( "github.com/lxc/incus/internal/server/cluster/request" "github.com/lxc/incus/internal/server/db" dbCluster "github.com/lxc/incus/internal/server/db/cluster" - "github.com/lxc/incus/internal/server/network/openvswitch" + "github.com/lxc/incus/internal/server/network/ovn" "github.com/lxc/incus/internal/server/state" localUtil "github.com/lxc/incus/internal/server/util" "github.com/lxc/incus/internal/version" @@ -631,7 +631,7 @@ func (d *common) Update(config *api.NetworkACLPut, clientType request.ClientType // If there are affected OVN networks, then apply the changes, but only if the request type is normal. // This way we won't apply the same changes multiple times for each cluster member. if len(aclOVNNets) > 0 && clientType == request.ClientTypeNormal { - client, err := openvswitch.NewOVN(d.state) + client, err := ovn.NewOVN(d.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } diff --git a/internal/server/network/driver_ovn.go b/internal/server/network/driver_ovn.go index 3de7494f49a..446093425c3 100644 --- a/internal/server/network/driver_ovn.go +++ b/internal/server/network/driver_ovn.go @@ -27,6 +27,7 @@ import ( "github.com/lxc/incus/internal/server/locking" "github.com/lxc/incus/internal/server/network/acl" "github.com/lxc/incus/internal/server/network/openvswitch" + networkOVN "github.com/lxc/incus/internal/server/network/ovn" "github.com/lxc/incus/internal/server/project" localUtil "github.com/lxc/incus/internal/server/util" internalUtil "github.com/lxc/incus/internal/util" @@ -129,7 +130,7 @@ func (n *ovn) State() (*api.NetworkState, error) { }) } - client, err := openvswitch.NewOVN(n.state) + client, err := networkOVN.NewOVN(n.state) if err != nil { return nil, err } @@ -705,23 +706,23 @@ func (n *ovn) getNetworkPrefix() string { } // getChassisGroup returns OVN chassis group name to use. -func (n *ovn) getChassisGroupName() openvswitch.OVNChassisGroup { - return openvswitch.OVNChassisGroup(n.getNetworkPrefix()) +func (n *ovn) getChassisGroupName() networkOVN.OVNChassisGroup { + return networkOVN.OVNChassisGroup(n.getNetworkPrefix()) } // getRouterName returns OVN logical router name to use. -func (n *ovn) getRouterName() openvswitch.OVNRouter { - return openvswitch.OVNRouter(fmt.Sprintf("%s-lr", n.getNetworkPrefix())) +func (n *ovn) getRouterName() networkOVN.OVNRouter { + return networkOVN.OVNRouter(fmt.Sprintf("%s-lr", n.getNetworkPrefix())) } // getRouterExtPortName returns OVN logical router external port name to use. -func (n *ovn) getRouterExtPortName() openvswitch.OVNRouterPort { - return openvswitch.OVNRouterPort(fmt.Sprintf("%s-lrp-ext", n.getRouterName())) +func (n *ovn) getRouterExtPortName() networkOVN.OVNRouterPort { + return networkOVN.OVNRouterPort(fmt.Sprintf("%s-lrp-ext", n.getRouterName())) } // getRouterIntPortName returns OVN logical router internal port name to use. -func (n *ovn) getRouterIntPortName() openvswitch.OVNRouterPort { - return openvswitch.OVNRouterPort(fmt.Sprintf("%s-lrp-int", n.getRouterName())) +func (n *ovn) getRouterIntPortName() networkOVN.OVNRouterPort { + return networkOVN.OVNRouterPort(fmt.Sprintf("%s-lrp-int", n.getRouterName())) } // getRouterMAC returns OVN router MAC address to use for ports. Uses a stable seed to return stable random MAC. @@ -817,27 +818,27 @@ func (n *ovn) getDNSSearchList() []string { } // getExtSwitchName returns OVN logical external switch name. -func (n *ovn) getExtSwitchName() openvswitch.OVNSwitch { - return openvswitch.OVNSwitch(fmt.Sprintf("%s-ls-ext", n.getNetworkPrefix())) +func (n *ovn) getExtSwitchName() networkOVN.OVNSwitch { + return networkOVN.OVNSwitch(fmt.Sprintf("%s-ls-ext", n.getNetworkPrefix())) } // getExtSwitchRouterPortName returns OVN logical external switch router port name. -func (n *ovn) getExtSwitchRouterPortName() openvswitch.OVNSwitchPort { - return openvswitch.OVNSwitchPort(fmt.Sprintf("%s-lsp-router", n.getExtSwitchName())) +func (n *ovn) getExtSwitchRouterPortName() networkOVN.OVNSwitchPort { + return networkOVN.OVNSwitchPort(fmt.Sprintf("%s-lsp-router", n.getExtSwitchName())) } // getExtSwitchProviderPortName returns OVN logical external switch provider port name. -func (n *ovn) getExtSwitchProviderPortName() openvswitch.OVNSwitchPort { - return openvswitch.OVNSwitchPort(fmt.Sprintf("%s-lsp-provider", n.getExtSwitchName())) +func (n *ovn) getExtSwitchProviderPortName() networkOVN.OVNSwitchPort { + return networkOVN.OVNSwitchPort(fmt.Sprintf("%s-lsp-provider", n.getExtSwitchName())) } // getIntSwitchName returns OVN logical internal switch name. -func (n *ovn) getIntSwitchName() openvswitch.OVNSwitch { +func (n *ovn) getIntSwitchName() networkOVN.OVNSwitch { return acl.OVNIntSwitchName(n.id) } // getIntSwitchRouterPortName returns OVN logical internal switch router port name. -func (n *ovn) getIntSwitchRouterPortName() openvswitch.OVNSwitchPort { +func (n *ovn) getIntSwitchRouterPortName() networkOVN.OVNSwitchPort { return acl.OVNIntSwitchRouterPortName(n.id) } @@ -847,13 +848,13 @@ func (n *ovn) getIntSwitchInstancePortPrefix() string { } // getLoadBalancerName returns OVN load balancer name to use for a listen address. -func (n *ovn) getLoadBalancerName(listenAddress string) openvswitch.OVNLoadBalancer { - return openvswitch.OVNLoadBalancer(fmt.Sprintf("%s-lb-%s", n.getNetworkPrefix(), listenAddress)) +func (n *ovn) getLoadBalancerName(listenAddress string) networkOVN.OVNLoadBalancer { + return networkOVN.OVNLoadBalancer(fmt.Sprintf("%s-lb-%s", n.getNetworkPrefix(), listenAddress)) } // getLogicalRouterPeerPortName returns OVN logical router port name to use for a peer connection. -func (n *ovn) getLogicalRouterPeerPortName(peerNetworkID int64) openvswitch.OVNRouterPort { - return openvswitch.OVNRouterPort(fmt.Sprintf("%s-lrp-peer-net%d", n.getRouterName(), peerNetworkID)) +func (n *ovn) getLogicalRouterPeerPortName(peerNetworkID int64) networkOVN.OVNRouterPort { + return networkOVN.OVNRouterPort(fmt.Sprintf("%s-lrp-peer-net%d", n.getRouterName(), peerNetworkID)) } // setupUplinkPort initialises the uplink connection. Returns the derived ovnUplinkVars settings used @@ -1838,7 +1839,7 @@ func (n *ovn) setup(update bool) error { revert := revert.New() defer revert.Fail() - client, err := openvswitch.NewOVN(n.state) + client, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -2094,7 +2095,7 @@ func (n *ovn) setup(update bool) error { defaultIPv4Route := net.IPNet{IP: net.IPv4zero, Mask: net.CIDRMask(0, 32)} defaultIPv6Route := net.IPNet{IP: net.IPv6zero, Mask: net.CIDRMask(0, 128)} deleteRoutes := []net.IPNet{defaultIPv4Route, defaultIPv6Route} - defaultRoutes := make([]openvswitch.OVNRouterRoute, 0, 2) + defaultRoutes := make([]networkOVN.OVNRouterRoute, 0, 2) if routerIntPortIPv4Net != nil { // If l3only mode is enabled then each instance IPv4 will get its own /32 route added when @@ -2102,7 +2103,7 @@ func (n *ovn) setup(update bool) error { // subnet escaping onto the uplink network we add a less specific discard route for the // whole internal subnet. if util.IsTrue(n.config["ipv4.l3only"]) { - defaultRoutes = append(defaultRoutes, openvswitch.OVNRouterRoute{ + defaultRoutes = append(defaultRoutes, networkOVN.OVNRouterRoute{ Prefix: *routerIntPortIPv4Net, Discard: true, }) @@ -2117,7 +2118,7 @@ func (n *ovn) setup(update bool) error { // subnet escaping onto the uplink network we add a less specific discard route for the // whole internal subnet. if util.IsTrue(n.config["ipv6.l3only"]) { - defaultRoutes = append(defaultRoutes, openvswitch.OVNRouterRoute{ + defaultRoutes = append(defaultRoutes, networkOVN.OVNRouterRoute{ Prefix: *routerIntPortIPv6Net, Discard: true, }) @@ -2127,7 +2128,7 @@ func (n *ovn) setup(update bool) error { } if uplinkNet.routerExtGwIPv4 != nil { - defaultRoutes = append(defaultRoutes, openvswitch.OVNRouterRoute{ + defaultRoutes = append(defaultRoutes, networkOVN.OVNRouterRoute{ Prefix: defaultIPv4Route, NextHop: uplinkNet.routerExtGwIPv4, Port: n.getRouterExtPortName(), @@ -2135,7 +2136,7 @@ func (n *ovn) setup(update bool) error { } if uplinkNet.routerExtGwIPv6 != nil { - defaultRoutes = append(defaultRoutes, openvswitch.OVNRouterRoute{ + defaultRoutes = append(defaultRoutes, networkOVN.OVNRouterRoute{ Prefix: defaultIPv6Route, NextHop: uplinkNet.routerExtGwIPv6, Port: n.getRouterExtPortName(), @@ -2206,7 +2207,7 @@ func (n *ovn) setup(update bool) error { } // Setup IP allocation config on logical switch. - err = client.LogicalSwitchSetIPAllocation(n.getIntSwitchName(), &openvswitch.OVNIPAllocationOpts{ + err = client.LogicalSwitchSetIPAllocation(n.getIntSwitchName(), &networkOVN.OVNIPAllocationOpts{ PrefixIPv4: routerIntPortIPv4Net, PrefixIPv6: routerIntPortIPv6Net, ExcludeIPv4: dhcpReserveIPv4s, @@ -2247,7 +2248,7 @@ func (n *ovn) setup(update bool) error { } // Configure DHCP option sets. - var dhcpv4UUID, dhcpv6UUID openvswitch.OVNDHCPOptionsUUID + var dhcpv4UUID, dhcpv6UUID networkOVN.OVNDHCPOptionsUUID dhcpV4Subnet := n.DHCPv4Subnet() dhcpV6Subnet := n.DHCPv6Subnet() @@ -2259,7 +2260,7 @@ func (n *ovn) setup(update bool) error { } // DHCP option records to delete if DHCP is being disabled. - var deleteDHCPRecords []openvswitch.OVNDHCPOptionsUUID + var deleteDHCPRecords []networkOVN.OVNDHCPOptionsUUID for _, existingOpt := range existingOpts { if existingOpt.CIDR.IP.To4() == nil { @@ -2297,7 +2298,7 @@ func (n *ovn) setup(update bool) error { dhcpV4Netmask = "255.255.255.255" } - err = client.LogicalSwitchDHCPv4OptionsSet(n.getIntSwitchName(), dhcpv4UUID, dhcpV4Subnet, &openvswitch.OVNDHCPv4Opts{ + err = client.LogicalSwitchDHCPv4OptionsSet(n.getIntSwitchName(), dhcpv4UUID, dhcpV4Subnet, &networkOVN.OVNDHCPv4Opts{ ServerID: routerIntPortIPv4, ServerMAC: routerMAC, Router: routerIntPortIPv4, @@ -2314,7 +2315,7 @@ func (n *ovn) setup(update bool) error { // Create DHCPv6 options for internal switch. if dhcpV6Subnet != nil { - err = client.LogicalSwitchDHCPv6OptionsSet(n.getIntSwitchName(), dhcpv6UUID, dhcpV6Subnet, &openvswitch.OVNDHCPv6Opts{ + err = client.LogicalSwitchDHCPv6OptionsSet(n.getIntSwitchName(), dhcpv6UUID, dhcpV6Subnet, &networkOVN.OVNDHCPv6Opts{ ServerID: routerMAC, RecursiveDNSServer: uplinkNet.dnsIPv6, DNSSearchList: n.getDNSSearchList(), @@ -2326,11 +2327,11 @@ func (n *ovn) setup(update bool) error { // Set IPv6 router advertisement settings. if routerIntPortIPv6Net != nil { - adressMode := openvswitch.OVNIPv6AddressModeSLAAC + adressMode := networkOVN.OVNIPv6AddressModeSLAAC if dhcpV6Subnet != nil { - adressMode = openvswitch.OVNIPv6AddressModeDHCPStateless + adressMode = networkOVN.OVNIPv6AddressModeDHCPStateless if util.IsTrue(n.config["ipv6.dhcp.stateful"]) { - adressMode = openvswitch.OVNIPv6AddressModeDHCPStateful + adressMode = networkOVN.OVNIPv6AddressModeDHCPStateful } } @@ -2339,7 +2340,7 @@ func (n *ovn) setup(update bool) error { recursiveDNSServer = uplinkNet.dnsIPv6[0] // OVN only supports 1 RA DNS server. } - err = client.LogicalRouterPortSetIPv6Advertisements(n.getRouterIntPortName(), &openvswitch.OVNIPv6RAOpts{ + err = client.LogicalRouterPortSetIPv6Advertisements(n.getRouterIntPortName(), &networkOVN.OVNIPv6RAOpts{ AddressMode: adressMode, SendPeriodic: true, DNSSearchList: n.getDNSSearchList(), @@ -2418,12 +2419,12 @@ func (n *ovn) setup(update bool) error { // Optionally excludePeers takes a list of peer network IDs to exclude from the router policy. This is useful // when removing a peer connection as it allows the security policy to be removed from OVN for that peer before the // peer connection has been removed from the database. -func (n *ovn) logicalRouterPolicySetup(client *openvswitch.OVN, excludePeers ...int64) error { +func (n *ovn) logicalRouterPolicySetup(client *networkOVN.OVN, excludePeers ...int64) error { extRouterPort := n.getRouterExtPortName() intRouterPort := n.getRouterIntPortName() addrSetPrefix := acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID()) - policies := []openvswitch.OVNRouterPolicy{ + policies := []networkOVN.OVNRouterPolicy{ { // Allow IPv6 packets arriving from internal router port with valid source address. Priority: ovnRouterPolicyPeerAllowPriority, @@ -2459,11 +2460,11 @@ func (n *ovn) logicalRouterPolicySetup(client *openvswitch.OVN, excludePeers ... // Associate the rules with the local peering port so we can identify them later if needed. comment := n.getLogicalRouterPeerPortName(targetOVNNet.ID()) - policies = append(policies, openvswitch.OVNRouterPolicy{ + policies = append(policies, networkOVN.OVNRouterPolicy{ Priority: ovnRouterPolicyPeerDropPriority, Match: fmt.Sprintf(`(inport == "%s" && ip6 && ip6.src == $%s_ip6) // %s`, extRouterPort, targetAddrSetPrefix, comment), Action: "drop", - }, openvswitch.OVNRouterPolicy{ + }, networkOVN.OVNRouterPolicy{ Priority: ovnRouterPolicyPeerDropPriority, Match: fmt.Sprintf(`(inport == "%s" && ip4 && ip4.src == $%s_ip4) // %s`, extRouterPort, targetAddrSetPrefix, comment), Action: "drop", @@ -2481,7 +2482,7 @@ func (n *ovn) logicalRouterPolicySetup(client *openvswitch.OVN, excludePeers ... // ensureNetworkPortGroup ensures that the network level port group (used for classifying NICs connected to this // network as internal) exists. func (n *ovn) ensureNetworkPortGroup(projectID int64) error { - client, err := openvswitch.NewOVN(n.state) + client, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -2509,7 +2510,7 @@ func (n *ovn) ensureNetworkPortGroup(projectID int64) error { // The chassis priority value is a stable-random value derived from chassis group name and node ID. This is so we // don't end up using the same chassis for the primary uplink chassis for all OVN networks in a cluster. func (n *ovn) addChassisGroupEntry() error { - client, err := openvswitch.NewOVN(n.state) + client, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -2574,7 +2575,7 @@ func (n *ovn) addChassisGroupEntry() error { // deleteChassisGroupEntry deletes an entry for the local OVS chassis from the OVN logical network's chassis group. func (n *ovn) deleteChassisGroupEntry() error { - client, err := openvswitch.NewOVN(n.state) + client, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -2604,7 +2605,7 @@ func (n *ovn) Delete(clientType request.ClientType) error { } if clientType == request.ClientTypeNormal { - client, err := openvswitch.NewOVN(n.state) + client, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -2681,7 +2682,7 @@ func (n *ovn) Delete(clientType request.ClientType) error { return fmt.Errorf("Failed loading network forwards: %w", err) } - loadBalancers := make([]openvswitch.OVNLoadBalancer, 0, len(forwardListenAddresses)+len(loadBalancerListenAddresses)) + loadBalancers := make([]networkOVN.OVNLoadBalancer, 0, len(forwardListenAddresses)+len(loadBalancerListenAddresses)) for _, listenAddress := range forwardListenAddresses { loadBalancers = append(loadBalancers, n.getLoadBalancerName(listenAddress)) } @@ -2975,10 +2976,10 @@ func (n *ovn) Update(newNetwork api.NetworkPut, targetNode string, clientType re return fmt.Errorf("Failed getting network ACL IDs for security ACL update: %w", err) } - addChangeSet := map[openvswitch.OVNPortGroup][]openvswitch.OVNSwitchPortUUID{} - removeChangeSet := map[openvswitch.OVNPortGroup][]openvswitch.OVNSwitchPortUUID{} + addChangeSet := map[networkOVN.OVNPortGroup][]networkOVN.OVNSwitchPortUUID{} + removeChangeSet := map[networkOVN.OVNPortGroup][]networkOVN.OVNSwitchPortUUID{} - client, err := openvswitch.NewOVN(n.state) + client, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -3171,8 +3172,8 @@ func (n *ovn) Update(newNetwork api.NetworkPut, targetNode string, clientType re } // getInstanceDevicePortName returns the switch port name to use for an instance device. -func (n *ovn) getInstanceDevicePortName(instanceUUID string, deviceName string) openvswitch.OVNSwitchPort { - return openvswitch.OVNSwitchPort(fmt.Sprintf("%s-%s-%s", n.getIntSwitchInstancePortPrefix(), instanceUUID, deviceName)) +func (n *ovn) getInstanceDevicePortName(instanceUUID string, deviceName string) networkOVN.OVNSwitchPort { + return networkOVN.OVNSwitchPort(fmt.Sprintf("%s-%s-%s", n.getIntSwitchInstancePortPrefix(), instanceUUID, deviceName)) } // instanceDevicePortRoutesParse parses the instance NIC device config for internal routes and external routes. @@ -3320,7 +3321,7 @@ func (n *ovn) InstanceDevicePortAdd(instanceUUID string, deviceName string, devi revert := revert.New() defer revert.Fail() - client, err := openvswitch.NewOVN(n.state) + client, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -3369,7 +3370,7 @@ func (n *ovn) hasDHCPv4Reservation(dhcpReservations []iprange.Range, ip net.IP) // InstanceDevicePortStart sets up an instance device port to the internal logical switch. // Accepts a list of ACLs being removed from the NIC device (if called as part of a NIC update). // Returns the logical switch port name and a list of IPs that were allocated to the port for DNS. -func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACLsRemove []string) (openvswitch.OVNSwitchPort, []net.IP, error) { +func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACLsRemove []string) (networkOVN.OVNSwitchPort, []net.IP, error) { if opts.InstanceUUID == "" { return "", nil, fmt.Errorf("Instance UUID is required") } @@ -3401,7 +3402,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL revert := revert.New() defer revert.Fail() - client, err := openvswitch.NewOVN(n.state) + client, err := networkOVN.NewOVN(n.state) if err != nil { return "", nil, fmt.Errorf("Failed to get OVN client: %w", err) } @@ -3416,7 +3417,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL dhcpv4Subnet := n.DHCPv4Subnet() dhcpv6Subnet := n.DHCPv6Subnet() - var dhcpV4ID, dhcpv6ID openvswitch.OVNDHCPOptionsUUID + var dhcpV4ID, dhcpv6ID networkOVN.OVNDHCPOptionsUUID if dhcpv4Subnet != nil || dhcpv6Subnet != nil { // Find existing DHCP options set for IPv4 and IPv6 and update them instead of adding sets. @@ -3522,7 +3523,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL instancePortName := n.getInstanceDevicePortName(opts.InstanceUUID, opts.DeviceName) - var nestedPortParentName openvswitch.OVNSwitchPort + var nestedPortParentName networkOVN.OVNSwitchPort var nestedPortVLAN uint16 if opts.DeviceConfig["nested"] != "" { nestedPortParentName = n.getInstanceDevicePortName(opts.InstanceUUID, opts.DeviceConfig["nested"]) @@ -3538,7 +3539,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL // to configure the port as needed. This is required in case the OVN northbound database was unavailable // when the instance NIC was stopped and was unable to remove the port on last stop, which would otherwise // prevent future NIC starts. - err = client.LogicalSwitchPortAdd(n.getIntSwitchName(), instancePortName, &openvswitch.OVNSwitchPortOpts{ + err = client.LogicalSwitchPortAdd(n.getIntSwitchName(), instancePortName, &networkOVN.OVNSwitchPortOpts{ DHCPv4OptsID: dhcpV4ID, DHCPv6OptsID: dhcpv6ID, MAC: mac, @@ -3656,7 +3657,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL } } - var routes []openvswitch.OVNRouterRoute + var routes []networkOVN.OVNRouterRoute // In l3only mode we add the instance port's IPs as static routes to the router. if util.IsTrue(n.config["ipv4.l3only"]) && dnsIPv4 != nil { @@ -3680,7 +3681,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL return "", nil, fmt.Errorf("Cannot add static route for %q as target IP is not set", internalRoute.String()) } - routes = append(routes, openvswitch.OVNRouterRoute{ + routes = append(routes, networkOVN.OVNRouterRoute{ Prefix: *internalRoute, NextHop: targetIP, Port: n.getRouterIntPortName(), @@ -3698,7 +3699,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL return "", nil, fmt.Errorf("Cannot add static route for %q as target IP is not set", externalRoute.String()) } - routes = append(routes, openvswitch.OVNRouterRoute{ + routes = append(routes, networkOVN.OVNRouterRoute{ Prefix: *externalRoute, NextHop: targetIP, Port: n.getRouterIntPortName(), @@ -3764,7 +3765,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL err = n.forPeers(func(targetOVNNet *ovn) error { targetRouterName := targetOVNNet.getRouterName() targetRouterPort := targetOVNNet.getLogicalRouterPeerPortName(n.ID()) - targetRouterRoutes := make([]openvswitch.OVNRouterRoute, 0, len(routes)) + targetRouterRoutes := make([]networkOVN.OVNRouterRoute, 0, len(routes)) for _, route := range routes { nexthop := routerIntPortIPv4 if route.Prefix.IP.To4() == nil { @@ -3775,7 +3776,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL continue // Skip routes that cannot be supported by local router. } - targetRouterRoutes = append(targetRouterRoutes, openvswitch.OVNRouterRoute{ + targetRouterRoutes = append(targetRouterRoutes, networkOVN.OVNRouterRoute{ Prefix: route.Prefix, NextHop: nexthop, Port: targetRouterPort, @@ -3807,8 +3808,8 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL } // Apply Security ACL port group settings. - addChangeSet := map[openvswitch.OVNPortGroup][]openvswitch.OVNSwitchPortUUID{} - removeChangeSet := map[openvswitch.OVNPortGroup][]openvswitch.OVNSwitchPortUUID{} + addChangeSet := map[networkOVN.OVNPortGroup][]networkOVN.OVNSwitchPortUUID{} + removeChangeSet := map[networkOVN.OVNPortGroup][]networkOVN.OVNSwitchPortUUID{} // Get logical port UUID. portUUID, err := client.LogicalSwitchPortUUID(instancePortName) @@ -3935,7 +3936,7 @@ func (n *ovn) InstanceDevicePortIPs(instanceUUID string, deviceName string) ([]n return nil, fmt.Errorf("Instance UUID is required") } - client, err := openvswitch.NewOVN(n.state) + client, err := networkOVN.NewOVN(n.state) if err != nil { return nil, fmt.Errorf("Failed to get OVN client: %w", err) } @@ -3951,7 +3952,7 @@ func (n *ovn) InstanceDevicePortIPs(instanceUUID string, deviceName string) ([]n } // InstanceDevicePortStop deletes an instance device port from the internal logical switch. -func (n *ovn) InstanceDevicePortStop(ovsExternalOVNPort openvswitch.OVNSwitchPort, opts *OVNInstanceNICStopOpts) error { +func (n *ovn) InstanceDevicePortStop(ovsExternalOVNPort networkOVN.OVNSwitchPort, opts *OVNInstanceNICStopOpts) error { // Decide whether to use OVS provided OVN port name or internally derived OVN port name. instancePortName := ovsExternalOVNPort source := "OVS" @@ -3964,7 +3965,7 @@ func (n *ovn) InstanceDevicePortStop(ovsExternalOVNPort openvswitch.OVNSwitchPor source = "internal" } - client, err := openvswitch.NewOVN(n.state) + client, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -4089,7 +4090,7 @@ func (n *ovn) InstanceDevicePortRemove(instanceUUID string, deviceName string, d revert := revert.New() defer revert.Fail() - client, err := openvswitch.NewOVN(n.state) + client, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -4342,7 +4343,7 @@ func (n *ovn) handleDependencyChange(uplinkName string, uplinkConfig map[string] if util.ValueInSlice("ovn.ingress_mode", changedKeys) { n.logger.Debug("Applying ingress mode changes from uplink network to instance NICs", logger.Ctx{"uplink": uplinkName}) - client, err := openvswitch.NewOVN(n.state) + client, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -4422,13 +4423,13 @@ func (n *ovn) handleDependencyChange(uplinkName string, uplinkConfig map[string] } // forwardFlattenVIPs flattens forwards into format compatible with OVN load balancers. -func (n *ovn) forwardFlattenVIPs(listenAddress net.IP, defaultTargetAddress net.IP, portMaps []*forwardPortMap) []openvswitch.OVNLoadBalancerVIP { - var vips []openvswitch.OVNLoadBalancerVIP +func (n *ovn) forwardFlattenVIPs(listenAddress net.IP, defaultTargetAddress net.IP, portMaps []*forwardPortMap) []networkOVN.OVNLoadBalancerVIP { + var vips []networkOVN.OVNLoadBalancerVIP if defaultTargetAddress != nil { - vips = append(vips, openvswitch.OVNLoadBalancerVIP{ + vips = append(vips, networkOVN.OVNLoadBalancerVIP{ ListenAddress: listenAddress, - Targets: []openvswitch.OVNLoadBalancerTarget{{Address: defaultTargetAddress}}, + Targets: []networkOVN.OVNLoadBalancerTarget{{Address: defaultTargetAddress}}, }) } @@ -4447,11 +4448,11 @@ func (n *ovn) forwardFlattenVIPs(listenAddress net.IP, defaultTargetAddress net. targetPort = portMap.target.ports[i] } - vips = append(vips, openvswitch.OVNLoadBalancerVIP{ + vips = append(vips, networkOVN.OVNLoadBalancerVIP{ ListenAddress: listenAddress, Protocol: portMap.protocol, ListenPort: lp, - Targets: []openvswitch.OVNLoadBalancerTarget{ + Targets: []networkOVN.OVNLoadBalancerTarget{ { Address: portMap.target.address, Port: targetPort, @@ -4552,7 +4553,7 @@ func (n *ovn) ForwardCreate(forward api.NetworkForwardsPost, clientType request. } } - client, err := openvswitch.NewOVN(n.state) + client, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -4571,7 +4572,7 @@ func (n *ovn) ForwardCreate(forward api.NetworkForwardsPost, clientType request. vips := n.forwardFlattenVIPs(net.ParseIP(forward.ListenAddress), net.ParseIP(forward.Config["target_address"]), portMaps) - err = client.LoadBalancerApply(n.getLoadBalancerName(forward.ListenAddress), []openvswitch.OVNRouter{n.getRouterName()}, []openvswitch.OVNSwitch{n.getIntSwitchName()}, vips...) + err = client.LoadBalancerApply(n.getLoadBalancerName(forward.ListenAddress), []networkOVN.OVNRouter{n.getRouterName()}, []networkOVN.OVNSwitch{n.getIntSwitchName()}, vips...) if err != nil { return fmt.Errorf("Failed applying OVN load balancer: %w", err) } @@ -4636,13 +4637,13 @@ func (n *ovn) ForwardUpdate(listenAddress string, req api.NetworkForwardPut, cli return nil // Nothing has changed. } - client, err := openvswitch.NewOVN(n.state) + client, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } vips := n.forwardFlattenVIPs(net.ParseIP(newForward.ListenAddress), net.ParseIP(newForward.Config["target_address"]), portMaps) - err = client.LoadBalancerApply(n.getLoadBalancerName(newForward.ListenAddress), []openvswitch.OVNRouter{n.getRouterName()}, []openvswitch.OVNSwitch{n.getIntSwitchName()}, vips...) + err = client.LoadBalancerApply(n.getLoadBalancerName(newForward.ListenAddress), []networkOVN.OVNRouter{n.getRouterName()}, []networkOVN.OVNSwitch{n.getIntSwitchName()}, vips...) if err != nil { return fmt.Errorf("Failed applying OVN load balancer: %w", err) } @@ -4652,7 +4653,7 @@ func (n *ovn) ForwardUpdate(listenAddress string, req api.NetworkForwardPut, cli portMaps, err := n.forwardValidate(net.ParseIP(curForward.ListenAddress), &curForward.NetworkForwardPut) if err == nil { vips := n.forwardFlattenVIPs(net.ParseIP(curForward.ListenAddress), net.ParseIP(curForward.Config["target_address"]), portMaps) - _ = client.LoadBalancerApply(n.getLoadBalancerName(curForward.ListenAddress), []openvswitch.OVNRouter{n.getRouterName()}, []openvswitch.OVNSwitch{n.getIntSwitchName()}, vips...) + _ = client.LoadBalancerApply(n.getLoadBalancerName(curForward.ListenAddress), []networkOVN.OVNRouter{n.getRouterName()}, []networkOVN.OVNSwitch{n.getIntSwitchName()}, vips...) _ = n.forwardBGPSetupPrefixes() } }) @@ -4699,7 +4700,7 @@ func (n *ovn) ForwardDelete(listenAddress string, clientType request.ClientType) return err } - client, err := openvswitch.NewOVN(n.state) + client, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -4738,12 +4739,12 @@ func (n *ovn) ForwardDelete(listenAddress string, clientType request.ClientType) } // loadBalancerFlattenVIPs flattens port maps into format compatible with OVN load balancers. -func (n *ovn) loadBalancerFlattenVIPs(listenAddress net.IP, portMaps []*loadBalancerPortMap) []openvswitch.OVNLoadBalancerVIP { - var vips []openvswitch.OVNLoadBalancerVIP +func (n *ovn) loadBalancerFlattenVIPs(listenAddress net.IP, portMaps []*loadBalancerPortMap) []networkOVN.OVNLoadBalancerVIP { + var vips []networkOVN.OVNLoadBalancerVIP for _, portMap := range portMaps { for i, lp := range portMap.listenPorts { - vip := openvswitch.OVNLoadBalancerVIP{ + vip := networkOVN.OVNLoadBalancerVIP{ ListenAddress: listenAddress, Protocol: portMap.protocol, ListenPort: lp, @@ -4762,7 +4763,7 @@ func (n *ovn) loadBalancerFlattenVIPs(listenAddress net.IP, portMaps []*loadBala targetPort = target.ports[i] } - vip.Targets = append(vip.Targets, openvswitch.OVNLoadBalancerTarget{ + vip.Targets = append(vip.Targets, networkOVN.OVNLoadBalancerTarget{ Address: target.address, Port: targetPort, }) @@ -4863,7 +4864,7 @@ func (n *ovn) LoadBalancerCreate(loadBalancer api.NetworkLoadBalancersPost, clie } } - client, err := openvswitch.NewOVN(n.state) + client, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -4882,7 +4883,7 @@ func (n *ovn) LoadBalancerCreate(loadBalancer api.NetworkLoadBalancersPost, clie vips := n.loadBalancerFlattenVIPs(net.ParseIP(loadBalancer.ListenAddress), portMaps) - err = client.LoadBalancerApply(n.getLoadBalancerName(loadBalancer.ListenAddress), []openvswitch.OVNRouter{n.getRouterName()}, []openvswitch.OVNSwitch{n.getIntSwitchName()}, vips...) + err = client.LoadBalancerApply(n.getLoadBalancerName(loadBalancer.ListenAddress), []networkOVN.OVNRouter{n.getRouterName()}, []networkOVN.OVNSwitch{n.getIntSwitchName()}, vips...) if err != nil { return fmt.Errorf("Failed applying OVN load balancer: %w", err) } @@ -4947,14 +4948,14 @@ func (n *ovn) LoadBalancerUpdate(listenAddress string, req api.NetworkLoadBalanc return nil // Nothing has changed. } - client, err := openvswitch.NewOVN(n.state) + client, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } vips := n.loadBalancerFlattenVIPs(net.ParseIP(newLoadBalancer.ListenAddress), portMaps) - err = client.LoadBalancerApply(n.getLoadBalancerName(newLoadBalancer.ListenAddress), []openvswitch.OVNRouter{n.getRouterName()}, []openvswitch.OVNSwitch{n.getIntSwitchName()}, vips...) + err = client.LoadBalancerApply(n.getLoadBalancerName(newLoadBalancer.ListenAddress), []networkOVN.OVNRouter{n.getRouterName()}, []networkOVN.OVNSwitch{n.getIntSwitchName()}, vips...) if err != nil { return fmt.Errorf("Failed applying OVN load balancer: %w", err) } @@ -4964,7 +4965,7 @@ func (n *ovn) LoadBalancerUpdate(listenAddress string, req api.NetworkLoadBalanc portMaps, err := n.loadBalancerValidate(net.ParseIP(curLoadBalancer.ListenAddress), &curLoadBalancer.NetworkLoadBalancerPut) if err == nil { vips := n.loadBalancerFlattenVIPs(net.ParseIP(curLoadBalancer.ListenAddress), portMaps) - _ = client.LoadBalancerApply(n.getLoadBalancerName(curLoadBalancer.ListenAddress), []openvswitch.OVNRouter{n.getRouterName()}, []openvswitch.OVNSwitch{n.getIntSwitchName()}, vips...) + _ = client.LoadBalancerApply(n.getLoadBalancerName(curLoadBalancer.ListenAddress), []networkOVN.OVNRouter{n.getRouterName()}, []networkOVN.OVNSwitch{n.getIntSwitchName()}, vips...) _ = n.forwardBGPSetupPrefixes() } }) @@ -5011,7 +5012,7 @@ func (n *ovn) LoadBalancerDelete(listenAddress string, clientType request.Client return err } - client, err := openvswitch.NewOVN(n.state) + client, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -5177,7 +5178,7 @@ func (n *ovn) PeerCreate(peer api.NetworkPeersPost) error { return fmt.Errorf("Only peerings in %q state can be setup", api.NetworkStatusCreated) } - client, err := openvswitch.NewOVN(n.state) + client, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -5245,13 +5246,13 @@ func (n *ovn) PeerCreate(peer api.NetworkPeersPost) error { // peerGetLocalOpts returns peering options prefilled with local router and local NIC routes config. // It can then be modified with the target peering network options. -func (n *ovn) peerGetLocalOpts(localNICRoutes []net.IPNet) (*openvswitch.OVNRouterPeering, error) { +func (n *ovn) peerGetLocalOpts(localNICRoutes []net.IPNet) (*networkOVN.OVNRouterPeering, error) { localRouterPortMAC, err := n.getRouterMAC() if err != nil { return nil, fmt.Errorf("Failed getting router MAC address: %w", err) } - opts := openvswitch.OVNRouterPeering{ + opts := networkOVN.OVNRouterPeering{ LocalRouter: n.getRouterName(), LocalRouterPortMAC: localRouterPortMAC, TargetRouterRoutes: localNICRoutes, // Pre-fill with local NIC routes. @@ -5292,7 +5293,7 @@ func (n *ovn) peerGetLocalOpts(localNICRoutes []net.IPNet) (*openvswitch.OVNRout // peerSetup applies the network peering configuration to both networks. // Accepts an OVN client, a target OVN network, and a set of OVNRouterPeering options pre-filled with local config. -func (n *ovn) peerSetup(client *openvswitch.OVN, targetOVNNet *ovn, opts openvswitch.OVNRouterPeering) error { +func (n *ovn) peerSetup(client *networkOVN.OVN, targetOVNNet *ovn, opts networkOVN.OVNRouterPeering) error { targetRouterMAC, err := targetOVNNet.getRouterMAC() if err != nil { return fmt.Errorf("Failed getting target router MAC address: %w", err) @@ -5445,14 +5446,14 @@ func (n *ovn) PeerDelete(peerName string) error { return fmt.Errorf("Target network is not ovn interface type") } - opts := openvswitch.OVNRouterPeering{ + opts := networkOVN.OVNRouterPeering{ LocalRouter: n.getRouterName(), LocalRouterPort: n.getLogicalRouterPeerPortName(targetOVNNet.ID()), TargetRouter: targetOVNNet.getRouterName(), TargetRouterPort: targetOVNNet.getLogicalRouterPeerPortName(n.ID()), } - client, err := openvswitch.NewOVN(n.state) + client, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } From 710ce0e8c34bc49ff171644e492aceadef9e21b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Mon, 18 Dec 2023 23:03:55 -0500 Subject: [PATCH 18/38] incusd/network/openvswitch: Rename to ovs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- internal/server/network/{openvswitch => ovs}/ovs.go | 2 +- .../network/{openvswitch => ovs}/schema/ovs/autoattach.go | 0 .../server/network/{openvswitch => ovs}/schema/ovs/bridge.go | 0 .../network/{openvswitch => ovs}/schema/ovs/controller.go | 0 .../{openvswitch => ovs}/schema/ovs/ct_timeout_policy.go | 0 .../server/network/{openvswitch => ovs}/schema/ovs/ct_zone.go | 0 .../server/network/{openvswitch => ovs}/schema/ovs/datapath.go | 0 .../schema/ovs/flow_sample_collector_set.go | 0 .../network/{openvswitch => ovs}/schema/ovs/flow_table.go | 0 .../server/network/{openvswitch => ovs}/schema/ovs/interface.go | 0 .../server/network/{openvswitch => ovs}/schema/ovs/ipfix.go | 0 .../server/network/{openvswitch => ovs}/schema/ovs/manager.go | 0 .../server/network/{openvswitch => ovs}/schema/ovs/mirror.go | 0 .../server/network/{openvswitch => ovs}/schema/ovs/model.go | 0 .../server/network/{openvswitch => ovs}/schema/ovs/netflow.go | 0 .../network/{openvswitch => ovs}/schema/ovs/open_vswitch.go | 0 internal/server/network/{openvswitch => ovs}/schema/ovs/port.go | 0 internal/server/network/{openvswitch => ovs}/schema/ovs/qos.go | 0 .../server/network/{openvswitch => ovs}/schema/ovs/queue.go | 0 .../server/network/{openvswitch => ovs}/schema/ovs/sflow.go | 0 internal/server/network/{openvswitch => ovs}/schema/ovs/ssl.go | 0 internal/server/network/{openvswitch => ovs}/shared.go | 2 +- 22 files changed, 2 insertions(+), 2 deletions(-) rename internal/server/network/{openvswitch => ovs}/ovs.go (99%) rename internal/server/network/{openvswitch => ovs}/schema/ovs/autoattach.go (100%) rename internal/server/network/{openvswitch => ovs}/schema/ovs/bridge.go (100%) rename internal/server/network/{openvswitch => ovs}/schema/ovs/controller.go (100%) rename internal/server/network/{openvswitch => ovs}/schema/ovs/ct_timeout_policy.go (100%) rename internal/server/network/{openvswitch => ovs}/schema/ovs/ct_zone.go (100%) rename internal/server/network/{openvswitch => ovs}/schema/ovs/datapath.go (100%) rename internal/server/network/{openvswitch => ovs}/schema/ovs/flow_sample_collector_set.go (100%) rename internal/server/network/{openvswitch => ovs}/schema/ovs/flow_table.go (100%) rename internal/server/network/{openvswitch => ovs}/schema/ovs/interface.go (100%) rename internal/server/network/{openvswitch => ovs}/schema/ovs/ipfix.go (100%) rename internal/server/network/{openvswitch => ovs}/schema/ovs/manager.go (100%) rename internal/server/network/{openvswitch => ovs}/schema/ovs/mirror.go (100%) rename internal/server/network/{openvswitch => ovs}/schema/ovs/model.go (100%) rename internal/server/network/{openvswitch => ovs}/schema/ovs/netflow.go (100%) rename internal/server/network/{openvswitch => ovs}/schema/ovs/open_vswitch.go (100%) rename internal/server/network/{openvswitch => ovs}/schema/ovs/port.go (100%) rename internal/server/network/{openvswitch => ovs}/schema/ovs/qos.go (100%) rename internal/server/network/{openvswitch => ovs}/schema/ovs/queue.go (100%) rename internal/server/network/{openvswitch => ovs}/schema/ovs/sflow.go (100%) rename internal/server/network/{openvswitch => ovs}/schema/ovs/ssl.go (100%) rename internal/server/network/{openvswitch => ovs}/shared.go (94%) diff --git a/internal/server/network/openvswitch/ovs.go b/internal/server/network/ovs/ovs.go similarity index 99% rename from internal/server/network/openvswitch/ovs.go rename to internal/server/network/ovs/ovs.go index d12515923c9..64d688593e2 100644 --- a/internal/server/network/openvswitch/ovs.go +++ b/internal/server/network/ovs/ovs.go @@ -1,4 +1,4 @@ -package openvswitch +package ovs import ( "fmt" diff --git a/internal/server/network/openvswitch/schema/ovs/autoattach.go b/internal/server/network/ovs/schema/ovs/autoattach.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovs/autoattach.go rename to internal/server/network/ovs/schema/ovs/autoattach.go diff --git a/internal/server/network/openvswitch/schema/ovs/bridge.go b/internal/server/network/ovs/schema/ovs/bridge.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovs/bridge.go rename to internal/server/network/ovs/schema/ovs/bridge.go diff --git a/internal/server/network/openvswitch/schema/ovs/controller.go b/internal/server/network/ovs/schema/ovs/controller.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovs/controller.go rename to internal/server/network/ovs/schema/ovs/controller.go diff --git a/internal/server/network/openvswitch/schema/ovs/ct_timeout_policy.go b/internal/server/network/ovs/schema/ovs/ct_timeout_policy.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovs/ct_timeout_policy.go rename to internal/server/network/ovs/schema/ovs/ct_timeout_policy.go diff --git a/internal/server/network/openvswitch/schema/ovs/ct_zone.go b/internal/server/network/ovs/schema/ovs/ct_zone.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovs/ct_zone.go rename to internal/server/network/ovs/schema/ovs/ct_zone.go diff --git a/internal/server/network/openvswitch/schema/ovs/datapath.go b/internal/server/network/ovs/schema/ovs/datapath.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovs/datapath.go rename to internal/server/network/ovs/schema/ovs/datapath.go diff --git a/internal/server/network/openvswitch/schema/ovs/flow_sample_collector_set.go b/internal/server/network/ovs/schema/ovs/flow_sample_collector_set.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovs/flow_sample_collector_set.go rename to internal/server/network/ovs/schema/ovs/flow_sample_collector_set.go diff --git a/internal/server/network/openvswitch/schema/ovs/flow_table.go b/internal/server/network/ovs/schema/ovs/flow_table.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovs/flow_table.go rename to internal/server/network/ovs/schema/ovs/flow_table.go diff --git a/internal/server/network/openvswitch/schema/ovs/interface.go b/internal/server/network/ovs/schema/ovs/interface.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovs/interface.go rename to internal/server/network/ovs/schema/ovs/interface.go diff --git a/internal/server/network/openvswitch/schema/ovs/ipfix.go b/internal/server/network/ovs/schema/ovs/ipfix.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovs/ipfix.go rename to internal/server/network/ovs/schema/ovs/ipfix.go diff --git a/internal/server/network/openvswitch/schema/ovs/manager.go b/internal/server/network/ovs/schema/ovs/manager.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovs/manager.go rename to internal/server/network/ovs/schema/ovs/manager.go diff --git a/internal/server/network/openvswitch/schema/ovs/mirror.go b/internal/server/network/ovs/schema/ovs/mirror.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovs/mirror.go rename to internal/server/network/ovs/schema/ovs/mirror.go diff --git a/internal/server/network/openvswitch/schema/ovs/model.go b/internal/server/network/ovs/schema/ovs/model.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovs/model.go rename to internal/server/network/ovs/schema/ovs/model.go diff --git a/internal/server/network/openvswitch/schema/ovs/netflow.go b/internal/server/network/ovs/schema/ovs/netflow.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovs/netflow.go rename to internal/server/network/ovs/schema/ovs/netflow.go diff --git a/internal/server/network/openvswitch/schema/ovs/open_vswitch.go b/internal/server/network/ovs/schema/ovs/open_vswitch.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovs/open_vswitch.go rename to internal/server/network/ovs/schema/ovs/open_vswitch.go diff --git a/internal/server/network/openvswitch/schema/ovs/port.go b/internal/server/network/ovs/schema/ovs/port.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovs/port.go rename to internal/server/network/ovs/schema/ovs/port.go diff --git a/internal/server/network/openvswitch/schema/ovs/qos.go b/internal/server/network/ovs/schema/ovs/qos.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovs/qos.go rename to internal/server/network/ovs/schema/ovs/qos.go diff --git a/internal/server/network/openvswitch/schema/ovs/queue.go b/internal/server/network/ovs/schema/ovs/queue.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovs/queue.go rename to internal/server/network/ovs/schema/ovs/queue.go diff --git a/internal/server/network/openvswitch/schema/ovs/sflow.go b/internal/server/network/ovs/schema/ovs/sflow.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovs/sflow.go rename to internal/server/network/ovs/schema/ovs/sflow.go diff --git a/internal/server/network/openvswitch/schema/ovs/ssl.go b/internal/server/network/ovs/schema/ovs/ssl.go similarity index 100% rename from internal/server/network/openvswitch/schema/ovs/ssl.go rename to internal/server/network/ovs/schema/ovs/ssl.go diff --git a/internal/server/network/openvswitch/shared.go b/internal/server/network/ovs/shared.go similarity index 94% rename from internal/server/network/openvswitch/shared.go rename to internal/server/network/ovs/shared.go index d4c5595f1ce..68b910bfb44 100644 --- a/internal/server/network/openvswitch/shared.go +++ b/internal/server/network/ovs/shared.go @@ -1,4 +1,4 @@ -package openvswitch +package ovs import ( "strconv" From 74c470fbb1540f5f6f49fdd1716111e362d01c6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Mon, 18 Dec 2023 23:05:15 -0500 Subject: [PATCH 19/38] Makefile: Update for OVS package MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 5a155ae2cab..a40a19c71e7 100644 --- a/Makefile +++ b/Makefile @@ -112,11 +112,11 @@ endif update-ovsdb: go install github.com/ovn-org/libovsdb/cmd/modelgen@main - rm -Rf internal/server/network/openvswitch/schema - mkdir internal/server/network/openvswitch/schema - curl -s https://raw.githubusercontent.com/openvswitch/ovs/v$(OVS_MINVER)/vswitchd/vswitch.ovsschema -o internal/server/network/openvswitch/schema/ovs.json - modelgen -o internal/server/network/openvswitch/schema/ovs internal/server/network/openvswitch/schema/ovs.json - rm internal/server/network/openvswitch/schema/*.json + rm -Rf internal/server/network/ovs/schema + mkdir internal/server/network/ovs/schema + curl -s https://raw.githubusercontent.com/openvswitch/ovs/v$(OVS_MINVER)/vswitchd/vswitch.ovsschema -o internal/server/network/ovs/schema/ovs.json + modelgen -o internal/server/network/ovs/schema/ovs internal/server/network/ovs/schema/ovs.json + rm internal/server/network/ovs/schema/*.json rm -Rf internal/server/network/ovn/schema mkdir internal/server/network/ovn/schema From a6bd7745cdaddc6af822b4a6e7085fa25b451390 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Mon, 18 Dec 2023 23:18:47 -0500 Subject: [PATCH 20/38] incusd: Update for OVS package rename MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- cmd/incusd/networks.go | 4 +-- internal/server/device/nic_bridged.go | 4 +-- internal/server/device/nic_ovn.go | 12 ++++----- internal/server/network/driver_bridge.go | 6 ++--- internal/server/network/driver_ovn.go | 27 +++++++++---------- .../server/network/network_utils_bridge.go | 6 ++--- .../server/network/network_utils_sriov.go | 4 +-- internal/server/network/ovn/ovn.go | 4 +-- 8 files changed, 33 insertions(+), 34 deletions(-) diff --git a/cmd/incusd/networks.go b/cmd/incusd/networks.go index 169e0f2bf9f..482eab587f3 100644 --- a/cmd/incusd/networks.go +++ b/cmd/incusd/networks.go @@ -27,7 +27,7 @@ import ( "github.com/lxc/incus/internal/server/instance/instancetype" "github.com/lxc/incus/internal/server/lifecycle" "github.com/lxc/incus/internal/server/network" - "github.com/lxc/incus/internal/server/network/openvswitch" + "github.com/lxc/incus/internal/server/network/ovs" "github.com/lxc/incus/internal/server/project" "github.com/lxc/incus/internal/server/request" "github.com/lxc/incus/internal/server/resources" @@ -865,7 +865,7 @@ func doNetworkGet(s *state.State, r *http.Request, allNodes bool, projectName st } else if util.PathExists(fmt.Sprintf("/sys/class/net/%s/bonding", apiNet.Name)) { apiNet.Type = "bond" } else { - ovs := openvswitch.NewOVS() + ovs := ovs.NewOVS() exists, _ := ovs.BridgeExists(apiNet.Name) if exists { apiNet.Type = "bridge" diff --git a/internal/server/device/nic_bridged.go b/internal/server/device/nic_bridged.go index 5ea6da43eee..8a5ea58ad55 100644 --- a/internal/server/device/nic_bridged.go +++ b/internal/server/device/nic_bridged.go @@ -27,7 +27,7 @@ import ( "github.com/lxc/incus/internal/server/instance/instancetype" "github.com/lxc/incus/internal/server/ip" "github.com/lxc/incus/internal/server/network" - "github.com/lxc/incus/internal/server/network/openvswitch" + "github.com/lxc/incus/internal/server/network/ovs" "github.com/lxc/incus/internal/server/resources" localUtil "github.com/lxc/incus/internal/server/util" internalUtil "github.com/lxc/incus/internal/util" @@ -1529,7 +1529,7 @@ func (d *nicBridged) setupNativeBridgePortVLANs(hostName string) error { // setupOVSBridgePortVLANs configures the bridge port with the specified VLAN settings on the openvswitch bridge. func (d *nicBridged) setupOVSBridgePortVLANs(hostName string) error { - ovs := openvswitch.NewOVS() + ovs := ovs.NewOVS() // Set port on bridge to specified untagged PVID. if d.config["vlan"] != "" { diff --git a/internal/server/device/nic_ovn.go b/internal/server/device/nic_ovn.go index b2e152a60a4..cf3c7008213 100644 --- a/internal/server/device/nic_ovn.go +++ b/internal/server/device/nic_ovn.go @@ -22,8 +22,8 @@ import ( "github.com/lxc/incus/internal/server/ip" "github.com/lxc/incus/internal/server/network" "github.com/lxc/incus/internal/server/network/acl" - "github.com/lxc/incus/internal/server/network/openvswitch" "github.com/lxc/incus/internal/server/network/ovn" + "github.com/lxc/incus/internal/server/network/ovs" "github.com/lxc/incus/internal/server/project" "github.com/lxc/incus/internal/server/resources" localUtil "github.com/lxc/incus/internal/server/util" @@ -409,7 +409,7 @@ func (d *nicOVN) Start() (*deviceConfig.RunConfig, error) { delete(saveData, "host_name") // Nested NICs don't have a host side interface. } else { if d.config["acceleration"] == "sriov" { - ovs := openvswitch.NewOVS() + ovs := ovs.NewOVS() if !ovs.HardwareOffloadingEnabled() { return nil, fmt.Errorf("SR-IOV acceleration requires hardware offloading be enabled in OVS") } @@ -456,7 +456,7 @@ func (d *nicOVN) Start() (*deviceConfig.RunConfig, error) { integrationBridgeNICName = vfRepresentor peerName = vfDev } else if d.config["acceleration"] == "vdpa" { - ovs := openvswitch.NewOVS() + ovs := ovs.NewOVS() if !ovs.HardwareOffloadingEnabled() { return nil, fmt.Errorf("SR-IOV acceleration requires hardware offloading be enabled in OVS") } @@ -609,7 +609,7 @@ func (d *nicOVN) Start() (*deviceConfig.RunConfig, error) { runConf := deviceConfig.RunConfig{} // Get local chassis ID for chassis group. - ovs := openvswitch.NewOVS() + ovs := ovs.NewOVS() chassisID, err := ovs.ChassisID() if err != nil { return nil, fmt.Errorf("Failed getting OVS Chassis ID: %w", err) @@ -825,7 +825,7 @@ func (d *nicOVN) Stop() (*deviceConfig.RunConfig, error) { // port name using the same regime it does for new ports. This part is only here in order to allow // instance ports generated under an older regime to be cleaned up properly. networkVethFillFromVolatile(d.config, v) - ovs := openvswitch.NewOVS() + ovs := ovs.NewOVS() var ovsExternalOVNPort string if d.config["nested"] == "" { ovsExternalOVNPort, err = ovs.InterfaceAssociatedOVNSwitchPort(d.config["host_name"]) @@ -1127,7 +1127,7 @@ func (d *nicOVN) setupHostNIC(hostName string, ovnPortName ovn.OVNSwitchPort, up // Attach host side veth interface to bridge. integrationBridge := d.state.GlobalConfig.NetworkOVNIntegrationBridge() - ovs := openvswitch.NewOVS() + ovs := ovs.NewOVS() err = ovs.BridgePortAdd(integrationBridge, hostName, true) if err != nil { return nil, err diff --git a/internal/server/network/driver_bridge.go b/internal/server/network/driver_bridge.go index bc0784e9f08..98181c4d1e7 100644 --- a/internal/server/network/driver_bridge.go +++ b/internal/server/network/driver_bridge.go @@ -28,7 +28,7 @@ import ( firewallDrivers "github.com/lxc/incus/internal/server/firewall/drivers" "github.com/lxc/incus/internal/server/ip" "github.com/lxc/incus/internal/server/network/acl" - "github.com/lxc/incus/internal/server/network/openvswitch" + "github.com/lxc/incus/internal/server/network/ovs" "github.com/lxc/incus/internal/server/project" localUtil "github.com/lxc/incus/internal/server/util" "github.com/lxc/incus/internal/server/warnings" @@ -581,7 +581,7 @@ func (n *bridge) setup(oldConfig map[string]string) error { // Create the bridge interface if doesn't exist. if !n.isRunning() { if n.config["bridge.driver"] == "openvswitch" { - ovs := openvswitch.NewOVS() + ovs := ovs.NewOVS() if !ovs.Installed() { return fmt.Errorf("Open vSwitch isn't installed on this system") } @@ -1440,7 +1440,7 @@ func (n *bridge) Stop() error { // Destroy the bridge interface if n.config["bridge.driver"] == "openvswitch" { - ovs := openvswitch.NewOVS() + ovs := ovs.NewOVS() err := ovs.BridgeDelete(n.name) if err != nil { return err diff --git a/internal/server/network/driver_ovn.go b/internal/server/network/driver_ovn.go index 446093425c3..cc65656daa7 100644 --- a/internal/server/network/driver_ovn.go +++ b/internal/server/network/driver_ovn.go @@ -26,8 +26,8 @@ import ( "github.com/lxc/incus/internal/server/ip" "github.com/lxc/incus/internal/server/locking" "github.com/lxc/incus/internal/server/network/acl" - "github.com/lxc/incus/internal/server/network/openvswitch" networkOVN "github.com/lxc/incus/internal/server/network/ovn" + "github.com/lxc/incus/internal/server/network/ovs" "github.com/lxc/incus/internal/server/project" localUtil "github.com/lxc/incus/internal/server/util" internalUtil "github.com/lxc/incus/internal/util" @@ -654,7 +654,7 @@ func (n *ovn) getUnderlayInfo() (uint32, net.IP, error) { return 0, fmt.Errorf("No matching interface found for OVN enscapsulation IP %q", findIP.String()) } - ovs := openvswitch.NewOVS() + ovs := ovs.NewOVS() encapIP, err := ovs.OVNEncapIP() if err != nil { return 0, nil, fmt.Errorf("Failed getting OVN enscapsulation IP from OVS: %w", err) @@ -1278,7 +1278,7 @@ func (n *ovn) startUplinkPortBridgeNative(uplinkNet Network, bridgeDevice string } // Create uplink OVS bridge if needed. - ovs := openvswitch.NewOVS() + ovs := ovs.NewOVS() err = ovs.BridgeAdd(vars.ovsBridge, true, nil, 0) if err != nil { return fmt.Errorf("Failed to create uplink OVS bridge %q: %w", vars.ovsBridge, err) @@ -1310,7 +1310,7 @@ func (n *ovn) startUplinkPortBridgeOVS(uplinkNet Network, bridgeDevice string) e defer revert.Fail() // If uplink is an openvswitch bridge, have OVN logical provider connect directly to it. - ovs := openvswitch.NewOVS() + ovs := ovs.NewOVS() err := ovs.OVNBridgeMappingAdd(bridgeDevice, uplinkNet.Name()) if err != nil { return fmt.Errorf("Failed to associate uplink OVS bridge %q to OVN provider %q: %w", bridgeDevice, uplinkNet.Name(), err) @@ -1386,7 +1386,7 @@ func (n *ovn) startUplinkPortPhysical(uplinkNet Network) error { } // Detect if uplink interface is a OVS bridge. - ovs := openvswitch.NewOVS() + ovs := ovs.NewOVS() isOVSBridge, _ := ovs.BridgeExists(uplinkHostName) if isOVSBridge { return n.startUplinkPortBridgeOVS(uplinkNet, uplinkHostName) @@ -1530,7 +1530,7 @@ func (n *ovn) deleteUplinkPortBridgeNative(uplinkNet Network) error { if !uplinkUsed { removeVeths = true - ovs := openvswitch.NewOVS() + ovs := ovs.NewOVS() err = ovs.OVNBridgeMappingDelete(vars.ovsBridge, uplinkNet.Name()) if err != nil { return err @@ -1576,7 +1576,7 @@ func (n *ovn) deleteUplinkPortBridgeOVS(uplinkNet Network, ovsBridge string) err // Remove uplink OVS bridge mapping if not in use by other OVN networks. if !uplinkUsed { - ovs := openvswitch.NewOVS() + ovs := ovs.NewOVS() err = ovs.OVNBridgeMappingDelete(ovsBridge, uplinkNet.Name()) if err != nil { return err @@ -1597,8 +1597,8 @@ func (n *ovn) deleteUplinkPortPhysical(uplinkNet Network) error { } // Detect if uplink interface is a OVS bridge. - ovs := openvswitch.NewOVS() - isOVSBridge, _ := ovs.BridgeExists(uplinkHostName) + vswitch := ovs.NewOVS() + isOVSBridge, _ := vswitch.BridgeExists(uplinkHostName) if isOVSBridge { return n.deleteUplinkPortBridgeOVS(uplinkNet, uplinkHostName) } @@ -1618,13 +1618,12 @@ func (n *ovn) deleteUplinkPortPhysical(uplinkNet Network) error { if !uplinkUsed { releaseIF = true - ovs := openvswitch.NewOVS() - err = ovs.OVNBridgeMappingDelete(vars.ovsBridge, uplinkNet.Name()) + err = vswitch.OVNBridgeMappingDelete(vars.ovsBridge, uplinkNet.Name()) if err != nil { return err } - err = ovs.BridgeDelete(vars.ovsBridge) + err = vswitch.BridgeDelete(vars.ovsBridge) if err != nil { return err } @@ -2516,7 +2515,7 @@ func (n *ovn) addChassisGroupEntry() error { } // Get local chassis ID for chassis group. - ovs := openvswitch.NewOVS() + ovs := ovs.NewOVS() chassisID, err := ovs.ChassisID() if err != nil { return fmt.Errorf("Failed getting OVS Chassis ID: %w", err) @@ -2581,7 +2580,7 @@ func (n *ovn) deleteChassisGroupEntry() error { } // Remove local chassis from chassis group. - ovs := openvswitch.NewOVS() + ovs := ovs.NewOVS() chassisID, err := ovs.ChassisID() if err != nil { return fmt.Errorf("Failed getting OVS Chassis ID: %w", err) diff --git a/internal/server/network/network_utils_bridge.go b/internal/server/network/network_utils_bridge.go index 6de14c783b5..e0bb5a4fc0a 100644 --- a/internal/server/network/network_utils_bridge.go +++ b/internal/server/network/network_utils_bridge.go @@ -6,7 +6,7 @@ import ( "strings" "github.com/lxc/incus/internal/server/ip" - "github.com/lxc/incus/internal/server/network/openvswitch" + "github.com/lxc/incus/internal/server/network/ovs" "github.com/lxc/incus/shared/util" ) @@ -64,7 +64,7 @@ func AttachInterface(bridgeName string, devName string) error { return err } } else { - ovs := openvswitch.NewOVS() + ovs := ovs.NewOVS() err := ovs.BridgePortAdd(bridgeName, devName, true) if err != nil { return err @@ -83,7 +83,7 @@ func DetachInterface(bridgeName string, devName string) error { return err } } else { - ovs := openvswitch.NewOVS() + ovs := ovs.NewOVS() err := ovs.BridgePortDelete(bridgeName, devName) if err != nil { return err diff --git a/internal/server/network/network_utils_sriov.go b/internal/server/network/network_utils_sriov.go index 17b24d952f1..0cc7a9879e4 100644 --- a/internal/server/network/network_utils_sriov.go +++ b/internal/server/network/network_utils_sriov.go @@ -17,7 +17,7 @@ import ( dbCluster "github.com/lxc/incus/internal/server/db/cluster" "github.com/lxc/incus/internal/server/device/pci" "github.com/lxc/incus/internal/server/ip" - "github.com/lxc/incus/internal/server/network/openvswitch" + "github.com/lxc/incus/internal/server/network/ovs" "github.com/lxc/incus/internal/server/state" "github.com/lxc/incus/shared/api" "github.com/lxc/incus/shared/logger" @@ -375,7 +375,7 @@ func SRIOVFindFreeVFAndRepresentor(state *state.State, ovsBridgeName string) (st return "", "", "", -1, fmt.Errorf("Failed to read directory %q: %w", sysClassNet, err) } - ovs := openvswitch.NewOVS() + ovs := ovs.NewOVS() // Get all ports on the integration bridge. ports, err := ovs.BridgePortList(ovsBridgeName) diff --git a/internal/server/network/ovn/ovn.go b/internal/server/network/ovn/ovn.go index 8087e7550cc..0eeb8c4dabb 100644 --- a/internal/server/network/ovn/ovn.go +++ b/internal/server/network/ovn/ovn.go @@ -15,9 +15,9 @@ import ( ovsdbModel "github.com/ovn-org/libovsdb/model" "github.com/lxc/incus/internal/linux" - "github.com/lxc/incus/internal/server/network/openvswitch" ovnNB "github.com/lxc/incus/internal/server/network/ovn/schema/ovn-nb" ovnSB "github.com/lxc/incus/internal/server/network/ovn/schema/ovn-sb" + "github.com/lxc/incus/internal/server/network/ovs" "github.com/lxc/incus/internal/server/state" "github.com/lxc/incus/shared/subprocess" ) @@ -26,7 +26,7 @@ import ( func NewOVN(s *state.State) (*OVN, error) { // Get database connection strings. nbConnection := s.GlobalConfig.NetworkOVNNorthboundConnection() - sbConnection, err := openvswitch.NewOVS().OVNSouthboundDBRemoteAddress() + sbConnection, err := ovs.NewOVS().OVNSouthboundDBRemoteAddress() if err != nil { return nil, fmt.Errorf("Failed to get OVN southbound connection string: %w", err) } From c0ed89095b36be462e25d9392f3bf8cd9cf287f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Mon, 18 Dec 2023 23:37:17 -0500 Subject: [PATCH 21/38] incusd: Fix import shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- cmd/incusd/networks.go | 4 +- internal/server/device/nic_bridged.go | 6 +- internal/server/device/nic_ovn.go | 26 +- internal/server/network/acl/driver_common.go | 6 +- internal/server/network/driver_bridge.go | 12 +- internal/server/network/driver_ovn.go | 350 +++++++++--------- .../server/network/network_utils_bridge.go | 8 +- .../server/network/network_utils_sriov.go | 4 +- 8 files changed, 208 insertions(+), 208 deletions(-) diff --git a/cmd/incusd/networks.go b/cmd/incusd/networks.go index 482eab587f3..49d5ede65e1 100644 --- a/cmd/incusd/networks.go +++ b/cmd/incusd/networks.go @@ -865,8 +865,8 @@ func doNetworkGet(s *state.State, r *http.Request, allNodes bool, projectName st } else if util.PathExists(fmt.Sprintf("/sys/class/net/%s/bonding", apiNet.Name)) { apiNet.Type = "bond" } else { - ovs := ovs.NewOVS() - exists, _ := ovs.BridgeExists(apiNet.Name) + vswitch := ovs.NewOVS() + exists, _ := vswitch.BridgeExists(apiNet.Name) if exists { apiNet.Type = "bridge" } else { diff --git a/internal/server/device/nic_bridged.go b/internal/server/device/nic_bridged.go index 8a5ea58ad55..6c1b3ade18d 100644 --- a/internal/server/device/nic_bridged.go +++ b/internal/server/device/nic_bridged.go @@ -1529,7 +1529,7 @@ func (d *nicBridged) setupNativeBridgePortVLANs(hostName string) error { // setupOVSBridgePortVLANs configures the bridge port with the specified VLAN settings on the openvswitch bridge. func (d *nicBridged) setupOVSBridgePortVLANs(hostName string) error { - ovs := ovs.NewOVS() + vswitch := ovs.NewOVS() // Set port on bridge to specified untagged PVID. if d.config["vlan"] != "" { @@ -1542,7 +1542,7 @@ func (d *nicBridged) setupOVSBridgePortVLANs(hostName string) error { // Order is important here, as vlan_mode is set to "access", assuming that vlan.tagged is not used. // If vlan.tagged is specified, then we expect it to also change the vlan_mode as needed. if d.config["vlan"] != "none" { - err := ovs.BridgePortSet(hostName, "vlan_mode=access", fmt.Sprintf("tag=%s", d.config["vlan"])) + err := vswitch.BridgePortSet(hostName, "vlan_mode=access", fmt.Sprintf("tag=%s", d.config["vlan"])) if err != nil { return err } @@ -1572,7 +1572,7 @@ func (d *nicBridged) setupOVSBridgePortVLANs(hostName string) error { // Also set the vlan_mode as needed from above. // Must come after the PortSet command used for setting "vlan" mode above so that the correct // vlan_mode is retained. - err = ovs.BridgePortSet(hostName, fmt.Sprintf("vlan_mode=%s", vlanMode), fmt.Sprintf("trunks=%s", strings.Join(vlanIDs, ","))) + err = vswitch.BridgePortSet(hostName, fmt.Sprintf("vlan_mode=%s", vlanMode), fmt.Sprintf("trunks=%s", strings.Join(vlanIDs, ","))) if err != nil { return err } diff --git a/internal/server/device/nic_ovn.go b/internal/server/device/nic_ovn.go index cf3c7008213..5d72a6e8d63 100644 --- a/internal/server/device/nic_ovn.go +++ b/internal/server/device/nic_ovn.go @@ -409,8 +409,8 @@ func (d *nicOVN) Start() (*deviceConfig.RunConfig, error) { delete(saveData, "host_name") // Nested NICs don't have a host side interface. } else { if d.config["acceleration"] == "sriov" { - ovs := ovs.NewOVS() - if !ovs.HardwareOffloadingEnabled() { + vswitch := ovs.NewOVS() + if !vswitch.HardwareOffloadingEnabled() { return nil, fmt.Errorf("SR-IOV acceleration requires hardware offloading be enabled in OVS") } @@ -456,8 +456,8 @@ func (d *nicOVN) Start() (*deviceConfig.RunConfig, error) { integrationBridgeNICName = vfRepresentor peerName = vfDev } else if d.config["acceleration"] == "vdpa" { - ovs := ovs.NewOVS() - if !ovs.HardwareOffloadingEnabled() { + vswitch := ovs.NewOVS() + if !vswitch.HardwareOffloadingEnabled() { return nil, fmt.Errorf("SR-IOV acceleration requires hardware offloading be enabled in OVS") } @@ -609,8 +609,8 @@ func (d *nicOVN) Start() (*deviceConfig.RunConfig, error) { runConf := deviceConfig.RunConfig{} // Get local chassis ID for chassis group. - ovs := ovs.NewOVS() - chassisID, err := ovs.ChassisID() + vswitch := ovs.NewOVS() + chassisID, err := vswitch.ChassisID() if err != nil { return nil, fmt.Errorf("Failed getting OVS Chassis ID: %w", err) } @@ -825,10 +825,10 @@ func (d *nicOVN) Stop() (*deviceConfig.RunConfig, error) { // port name using the same regime it does for new ports. This part is only here in order to allow // instance ports generated under an older regime to be cleaned up properly. networkVethFillFromVolatile(d.config, v) - ovs := ovs.NewOVS() + vswitch := ovs.NewOVS() var ovsExternalOVNPort string if d.config["nested"] == "" { - ovsExternalOVNPort, err = ovs.InterfaceAssociatedOVNSwitchPort(d.config["host_name"]) + ovsExternalOVNPort, err = vswitch.InterfaceAssociatedOVNSwitchPort(d.config["host_name"]) if err != nil { d.logger.Warn("Could not find OVN Switch port associated to OVS interface", logger.Ctx{"interface": d.config["host_name"]}) } @@ -850,7 +850,7 @@ func (d *nicOVN) Stop() (*deviceConfig.RunConfig, error) { integrationBridge := d.state.GlobalConfig.NetworkOVNIntegrationBridge() // Detach host-side end of veth pair from OVS integration bridge. - err = ovs.BridgePortDelete(integrationBridge, integrationBridgeNICName) + err = vswitch.BridgePortDelete(integrationBridge, integrationBridgeNICName) if err != nil { // Don't fail here as we want the postStop hook to run to clean up the local veth pair. d.logger.Error("Failed detaching interface from OVS integration bridge", logger.Ctx{"interface": integrationBridgeNICName, "bridge": integrationBridge, "err": err}) @@ -1127,16 +1127,16 @@ func (d *nicOVN) setupHostNIC(hostName string, ovnPortName ovn.OVNSwitchPort, up // Attach host side veth interface to bridge. integrationBridge := d.state.GlobalConfig.NetworkOVNIntegrationBridge() - ovs := ovs.NewOVS() - err = ovs.BridgePortAdd(integrationBridge, hostName, true) + vswitch := ovs.NewOVS() + err = vswitch.BridgePortAdd(integrationBridge, hostName, true) if err != nil { return nil, err } - revert.Add(func() { _ = ovs.BridgePortDelete(integrationBridge, hostName) }) + revert.Add(func() { _ = vswitch.BridgePortDelete(integrationBridge, hostName) }) // Link OVS port to OVN logical port. - err = ovs.InterfaceAssociateOVNSwitchPort(hostName, string(ovnPortName)) + err = vswitch.InterfaceAssociateOVNSwitchPort(hostName, string(ovnPortName)) if err != nil { return nil, err } diff --git a/internal/server/network/acl/driver_common.go b/internal/server/network/acl/driver_common.go index 85b808080c3..de4e85e6c91 100644 --- a/internal/server/network/acl/driver_common.go +++ b/internal/server/network/acl/driver_common.go @@ -631,7 +631,7 @@ func (d *common) Update(config *api.NetworkACLPut, clientType request.ClientType // If there are affected OVN networks, then apply the changes, but only if the request type is normal. // This way we won't apply the same changes multiple times for each cluster member. if len(aclOVNNets) > 0 && clientType == request.ClientTypeNormal { - client, err := ovn.NewOVN(d.state) + ovnnb, err := ovn.NewOVN(d.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -648,7 +648,7 @@ func (d *common) Update(config *api.NetworkACLPut, clientType request.ClientType // apply those rules to each network affected by the ACL, so pass the full list of OVN networks // affected by this ACL (either because the ACL is assigned directly or because it is assigned to // an OVN NIC in an instance or profile). - cleanup, err := OVNEnsureACLs(d.state, d.logger, client, d.projectName, aclNameIDs, aclOVNNets, []string{d.info.Name}, true) + cleanup, err := OVNEnsureACLs(d.state, d.logger, ovnnb, d.projectName, aclNameIDs, aclOVNNets, []string{d.info.Name}, true) if err != nil { return fmt.Errorf("Failed ensuring ACL is configured in OVN: %w", err) } @@ -657,7 +657,7 @@ func (d *common) Update(config *api.NetworkACLPut, clientType request.ClientType // Run unused port group cleanup in case any formerly referenced ACL in this ACL's rules means that // an ACL port group is now considered unused. - err = OVNPortGroupDeleteIfUnused(d.state, d.logger, client, d.projectName, nil, "", d.info.Name) + err = OVNPortGroupDeleteIfUnused(d.state, d.logger, ovnnb, d.projectName, nil, "", d.info.Name) if err != nil { return fmt.Errorf("Failed removing unused OVN port groups: %w", err) } diff --git a/internal/server/network/driver_bridge.go b/internal/server/network/driver_bridge.go index 98181c4d1e7..5325184116f 100644 --- a/internal/server/network/driver_bridge.go +++ b/internal/server/network/driver_bridge.go @@ -581,19 +581,19 @@ func (n *bridge) setup(oldConfig map[string]string) error { // Create the bridge interface if doesn't exist. if !n.isRunning() { if n.config["bridge.driver"] == "openvswitch" { - ovs := ovs.NewOVS() - if !ovs.Installed() { + vswitch := ovs.NewOVS() + if !vswitch.Installed() { return fmt.Errorf("Open vSwitch isn't installed on this system") } // Add and configure the interface in one operation to reduce the number of executions and // to avoid systemd-udevd from applying the default MACAddressPolicy=persistent policy. - err := ovs.BridgeAdd(n.name, false, bridge.Address, bridge.MTU) + err := vswitch.BridgeAdd(n.name, false, bridge.Address, bridge.MTU) if err != nil { return err } - revert.Add(func() { _ = ovs.BridgeDelete(n.name) }) + revert.Add(func() { _ = vswitch.BridgeDelete(n.name) }) } else { // Add and configure the interface in one operation to reduce the number of executions and // to avoid systemd-udevd from applying the default MACAddressPolicy=persistent policy. @@ -1440,8 +1440,8 @@ func (n *bridge) Stop() error { // Destroy the bridge interface if n.config["bridge.driver"] == "openvswitch" { - ovs := ovs.NewOVS() - err := ovs.BridgeDelete(n.name) + vswitch := ovs.NewOVS() + err := vswitch.BridgeDelete(n.name) if err != nil { return err } diff --git a/internal/server/network/driver_ovn.go b/internal/server/network/driver_ovn.go index cc65656daa7..9e2ff4848eb 100644 --- a/internal/server/network/driver_ovn.go +++ b/internal/server/network/driver_ovn.go @@ -130,20 +130,20 @@ func (n *ovn) State() (*api.NetworkState, error) { }) } - client, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewOVN(n.state) if err != nil { return nil, err } hwaddr, ok := n.config["bridge.hwaddr"] if !ok { - hwaddr, err = client.GetHardwareAddress(n.getRouterExtPortName()) + hwaddr, err = ovnnb.GetHardwareAddress(n.getRouterExtPortName()) if err != nil { return nil, err } } - chassis, err := client.GetLogicalRouterPortActiveChassisHostname(n.getRouterExtPortName()) + chassis, err := ovnnb.GetLogicalRouterPortActiveChassisHostname(n.getRouterExtPortName()) if err != nil { return nil, err } @@ -654,8 +654,8 @@ func (n *ovn) getUnderlayInfo() (uint32, net.IP, error) { return 0, fmt.Errorf("No matching interface found for OVN enscapsulation IP %q", findIP.String()) } - ovs := ovs.NewOVS() - encapIP, err := ovs.OVNEncapIP() + vswitch := ovs.NewOVS() + encapIP, err := vswitch.OVNEncapIP() if err != nil { return 0, nil, fmt.Errorf("Failed getting OVN enscapsulation IP from OVS: %w", err) } @@ -1278,20 +1278,20 @@ func (n *ovn) startUplinkPortBridgeNative(uplinkNet Network, bridgeDevice string } // Create uplink OVS bridge if needed. - ovs := ovs.NewOVS() - err = ovs.BridgeAdd(vars.ovsBridge, true, nil, 0) + vswitch := ovs.NewOVS() + err = vswitch.BridgeAdd(vars.ovsBridge, true, nil, 0) if err != nil { return fmt.Errorf("Failed to create uplink OVS bridge %q: %w", vars.ovsBridge, err) } // Connect OVS end veth interface to OVS bridge. - err = ovs.BridgePortAdd(vars.ovsBridge, vars.ovsEnd, true) + err = vswitch.BridgePortAdd(vars.ovsBridge, vars.ovsEnd, true) if err != nil { return fmt.Errorf("Failed to connect uplink veth interface %q to uplink OVS bridge %q: %w", vars.ovsEnd, vars.ovsBridge, err) } // Associate OVS bridge to logical OVN provider. - err = ovs.OVNBridgeMappingAdd(vars.ovsBridge, uplinkNet.Name()) + err = vswitch.OVNBridgeMappingAdd(vars.ovsBridge, uplinkNet.Name()) if err != nil { return fmt.Errorf("Failed to associate uplink OVS bridge %q to OVN provider %q: %w", vars.ovsBridge, uplinkNet.Name(), err) } @@ -1310,8 +1310,8 @@ func (n *ovn) startUplinkPortBridgeOVS(uplinkNet Network, bridgeDevice string) e defer revert.Fail() // If uplink is an openvswitch bridge, have OVN logical provider connect directly to it. - ovs := ovs.NewOVS() - err := ovs.OVNBridgeMappingAdd(bridgeDevice, uplinkNet.Name()) + vswitch := ovs.NewOVS() + err := vswitch.OVNBridgeMappingAdd(bridgeDevice, uplinkNet.Name()) if err != nil { return fmt.Errorf("Failed to associate uplink OVS bridge %q to OVN provider %q: %w", bridgeDevice, uplinkNet.Name(), err) } @@ -1386,8 +1386,8 @@ func (n *ovn) startUplinkPortPhysical(uplinkNet Network) error { } // Detect if uplink interface is a OVS bridge. - ovs := ovs.NewOVS() - isOVSBridge, _ := ovs.BridgeExists(uplinkHostName) + vswitch := ovs.NewOVS() + isOVSBridge, _ := vswitch.BridgeExists(uplinkHostName) if isOVSBridge { return n.startUplinkPortBridgeOVS(uplinkNet, uplinkHostName) } @@ -1415,19 +1415,19 @@ func (n *ovn) startUplinkPortPhysical(uplinkNet Network) error { } // Create uplink OVS bridge if needed. - err = ovs.BridgeAdd(vars.ovsBridge, true, nil, 0) + err = vswitch.BridgeAdd(vars.ovsBridge, true, nil, 0) if err != nil { return fmt.Errorf("Failed to create uplink OVS bridge %q: %w", vars.ovsBridge, err) } // Connect OVS end veth interface to OVS bridge. - err = ovs.BridgePortAdd(vars.ovsBridge, uplinkHostName, true) + err = vswitch.BridgePortAdd(vars.ovsBridge, uplinkHostName, true) if err != nil { return fmt.Errorf("Failed to connect uplink interface %q to uplink OVS bridge %q: %w", uplinkHostName, vars.ovsBridge, err) } // Associate OVS bridge to logical OVN provider. - err = ovs.OVNBridgeMappingAdd(vars.ovsBridge, uplinkNet.Name()) + err = vswitch.OVNBridgeMappingAdd(vars.ovsBridge, uplinkNet.Name()) if err != nil { return fmt.Errorf("Failed to associate uplink OVS bridge %q to OVN provider %q: %w", vars.ovsBridge, uplinkNet.Name(), err) } @@ -1530,13 +1530,13 @@ func (n *ovn) deleteUplinkPortBridgeNative(uplinkNet Network) error { if !uplinkUsed { removeVeths = true - ovs := ovs.NewOVS() - err = ovs.OVNBridgeMappingDelete(vars.ovsBridge, uplinkNet.Name()) + vswitch := ovs.NewOVS() + err = vswitch.OVNBridgeMappingDelete(vars.ovsBridge, uplinkNet.Name()) if err != nil { return err } - err = ovs.BridgeDelete(vars.ovsBridge) + err = vswitch.BridgeDelete(vars.ovsBridge) if err != nil { return err } @@ -1576,8 +1576,8 @@ func (n *ovn) deleteUplinkPortBridgeOVS(uplinkNet Network, ovsBridge string) err // Remove uplink OVS bridge mapping if not in use by other OVN networks. if !uplinkUsed { - ovs := ovs.NewOVS() - err = ovs.OVNBridgeMappingDelete(ovsBridge, uplinkNet.Name()) + vswitch := ovs.NewOVS() + err = vswitch.OVNBridgeMappingDelete(ovsBridge, uplinkNet.Name()) if err != nil { return err } @@ -1838,7 +1838,7 @@ func (n *ovn) setup(update bool) error { revert := revert.New() defer revert.Fail() - client, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -1955,23 +1955,23 @@ func (n *ovn) setup(update bool) error { } // Create chassis group. - err = client.ChassisGroupAdd(n.getChassisGroupName(), update) + err = ovnnb.ChassisGroupAdd(n.getChassisGroupName(), update) if err != nil { return err } if !update { - revert.Add(func() { _ = client.ChassisGroupDelete(n.getChassisGroupName()) }) + revert.Add(func() { _ = ovnnb.ChassisGroupDelete(n.getChassisGroupName()) }) } // Create logical router. - err = client.LogicalRouterAdd(n.getRouterName(), update) + err = ovnnb.LogicalRouterAdd(n.getRouterName(), update) if err != nil { return fmt.Errorf("Failed adding router: %w", err) } if !update { - revert.Add(func() { _ = client.LogicalRouterDelete(n.getRouterName()) }) + revert.Add(func() { _ = ovnnb.LogicalRouterDelete(n.getRouterName()) }) } // Configure logical router. @@ -1993,57 +1993,57 @@ func (n *ovn) setup(update bool) error { } if len(extRouterIPs) > 0 { - err = client.LogicalSwitchAdd(n.getExtSwitchName(), update) + err = ovnnb.LogicalSwitchAdd(n.getExtSwitchName(), update) if err != nil { return fmt.Errorf("Failed adding external switch: %w", err) } if !update { - revert.Add(func() { _ = client.LogicalSwitchDelete(n.getExtSwitchName()) }) + revert.Add(func() { _ = ovnnb.LogicalSwitchDelete(n.getExtSwitchName()) }) } // Create external router port. - err = client.LogicalRouterPortAdd(n.getRouterName(), n.getRouterExtPortName(), routerMAC, bridgeMTU, extRouterIPs, update) + err = ovnnb.LogicalRouterPortAdd(n.getRouterName(), n.getRouterExtPortName(), routerMAC, bridgeMTU, extRouterIPs, update) if err != nil { return fmt.Errorf("Failed adding external router port: %w", err) } if !update { - revert.Add(func() { _ = client.LogicalRouterPortDelete(n.getRouterExtPortName()) }) + revert.Add(func() { _ = ovnnb.LogicalRouterPortDelete(n.getRouterExtPortName()) }) } // Associate external router port to chassis group. - err = client.LogicalRouterPortLinkChassisGroup(n.getRouterExtPortName(), n.getChassisGroupName()) + err = ovnnb.LogicalRouterPortLinkChassisGroup(n.getRouterExtPortName(), n.getChassisGroupName()) if err != nil { return fmt.Errorf("Failed linking external router port to chassis group: %w", err) } // Create external switch port and link to router port. - err = client.LogicalSwitchPortAdd(n.getExtSwitchName(), n.getExtSwitchRouterPortName(), nil, update) + err = ovnnb.LogicalSwitchPortAdd(n.getExtSwitchName(), n.getExtSwitchRouterPortName(), nil, update) if err != nil { return fmt.Errorf("Failed adding external switch router port: %w", err) } if !update { - revert.Add(func() { _ = client.LogicalSwitchPortDelete(n.getExtSwitchRouterPortName()) }) + revert.Add(func() { _ = ovnnb.LogicalSwitchPortDelete(n.getExtSwitchRouterPortName()) }) } - err = client.LogicalSwitchPortLinkRouter(n.getExtSwitchRouterPortName(), n.getRouterExtPortName()) + err = ovnnb.LogicalSwitchPortLinkRouter(n.getExtSwitchRouterPortName(), n.getRouterExtPortName()) if err != nil { return fmt.Errorf("Failed linking external router port to external switch port: %w", err) } // Create external switch port and link to external provider network. - err = client.LogicalSwitchPortAdd(n.getExtSwitchName(), n.getExtSwitchProviderPortName(), nil, update) + err = ovnnb.LogicalSwitchPortAdd(n.getExtSwitchName(), n.getExtSwitchProviderPortName(), nil, update) if err != nil { return fmt.Errorf("Failed adding external switch provider port: %w", err) } if !update { - revert.Add(func() { _ = client.LogicalSwitchPortDelete(n.getExtSwitchProviderPortName()) }) + revert.Add(func() { _ = ovnnb.LogicalSwitchPortDelete(n.getExtSwitchProviderPortName()) }) } - err = client.LogicalSwitchPortLinkProviderNetwork(n.getExtSwitchProviderPortName(), uplinkNet.extSwitchProviderName) + err = ovnnb.LogicalSwitchPortLinkProviderNetwork(n.getExtSwitchProviderPortName(), uplinkNet.extSwitchProviderName) if err != nil { return fmt.Errorf("Failed linking external switch provider port to external provider network: %w", err) } @@ -2051,7 +2051,7 @@ func (n *ovn) setup(update bool) error { // Remove any existing SNAT rules on update. As currently these are only defined from the network // config rather than from any instance NIC config, so we can re-create the active config below. if update { - err = client.LogicalRouterSNATDeleteAll(n.getRouterName()) + err = ovnnb.LogicalRouterSNATDeleteAll(n.getRouterName()) if err != nil { return fmt.Errorf("Failed removing existing router SNAT rules: %w", err) } @@ -2068,7 +2068,7 @@ func (n *ovn) setup(update bool) error { } } - err = client.LogicalRouterSNATAdd(n.getRouterName(), routerIntPortIPv4Net, snatIP, update) + err = ovnnb.LogicalRouterSNATAdd(n.getRouterName(), routerIntPortIPv4Net, snatIP, update) if err != nil { return fmt.Errorf("Failed adding router IPv4 SNAT rule: %w", err) } @@ -2084,7 +2084,7 @@ func (n *ovn) setup(update bool) error { } } - err = client.LogicalRouterSNATAdd(n.getRouterName(), routerIntPortIPv6Net, snatIP, update) + err = ovnnb.LogicalRouterSNATAdd(n.getRouterName(), routerIntPortIPv6Net, snatIP, update) if err != nil { return fmt.Errorf("Failed adding router IPv6 SNAT rule: %w", err) } @@ -2143,14 +2143,14 @@ func (n *ovn) setup(update bool) error { } if len(deleteRoutes) > 0 { - err = client.LogicalRouterRouteDelete(n.getRouterName(), deleteRoutes...) + err = ovnnb.LogicalRouterRouteDelete(n.getRouterName(), deleteRoutes...) if err != nil { return fmt.Errorf("Failed removing default routes: %w", err) } } if len(defaultRoutes) > 0 { - err = client.LogicalRouterRouteAdd(n.getRouterName(), update, defaultRoutes...) + err = ovnnb.LogicalRouterRouteAdd(n.getRouterName(), update, defaultRoutes...) if err != nil { return fmt.Errorf("Failed adding default routes: %w", err) } @@ -2196,17 +2196,17 @@ func (n *ovn) setup(update bool) error { } // Create internal logical switch if not updating. - err = client.LogicalSwitchAdd(n.getIntSwitchName(), update) + err = ovnnb.LogicalSwitchAdd(n.getIntSwitchName(), update) if err != nil { return fmt.Errorf("Failed adding internal switch: %w", err) } if !update { - revert.Add(func() { _ = client.LogicalSwitchDelete(n.getIntSwitchName()) }) + revert.Add(func() { _ = ovnnb.LogicalSwitchDelete(n.getIntSwitchName()) }) } // Setup IP allocation config on logical switch. - err = client.LogicalSwitchSetIPAllocation(n.getIntSwitchName(), &networkOVN.OVNIPAllocationOpts{ + err = ovnnb.LogicalSwitchSetIPAllocation(n.getIntSwitchName(), &networkOVN.OVNIPAllocationOpts{ PrefixIPv4: routerIntPortIPv4Net, PrefixIPv6: routerIntPortIPv6Net, ExcludeIPv4: dhcpReserveIPv4s, @@ -2217,33 +2217,33 @@ func (n *ovn) setup(update bool) error { // Create internal switch address sets and add subnets to address set. if update { - err = client.AddressSetAdd(acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID()), intSubnets...) + err = ovnnb.AddressSetAdd(acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID()), intSubnets...) if err != nil { return fmt.Errorf("Failed adding internal subnet address set entries: %w", err) } } else { - err = client.AddressSetCreate(acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID()), intSubnets...) + err = ovnnb.AddressSetCreate(acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID()), intSubnets...) if err != nil { return fmt.Errorf("Failed creating internal subnet address set entries: %w", err) } - revert.Add(func() { _ = client.AddressSetDelete(acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID())) }) + revert.Add(func() { _ = ovnnb.AddressSetDelete(acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID())) }) } // Apply router security policy. - err = n.logicalRouterPolicySetup(client) + err = n.logicalRouterPolicySetup(ovnnb) if err != nil { return fmt.Errorf("Failed applying router security policy: %w", err) } // Create internal router port. - err = client.LogicalRouterPortAdd(n.getRouterName(), n.getRouterIntPortName(), routerMAC, bridgeMTU, intRouterIPs, update) + err = ovnnb.LogicalRouterPortAdd(n.getRouterName(), n.getRouterIntPortName(), routerMAC, bridgeMTU, intRouterIPs, update) if err != nil { return fmt.Errorf("Failed adding internal router port: %w", err) } if !update { - revert.Add(func() { _ = client.LogicalRouterPortDelete(n.getRouterIntPortName()) }) + revert.Add(func() { _ = ovnnb.LogicalRouterPortDelete(n.getRouterIntPortName()) }) } // Configure DHCP option sets. @@ -2253,7 +2253,7 @@ func (n *ovn) setup(update bool) error { if update { // Find first existing DHCP options set for IPv4 and IPv6 and update them instead of adding sets. - existingOpts, err := client.LogicalSwitchDHCPOptionsGet(n.getIntSwitchName()) + existingOpts, err := ovnnb.LogicalSwitchDHCPOptionsGet(n.getIntSwitchName()) if err != nil { return fmt.Errorf("Failed getting existing DHCP settings for internal switch: %w", err) } @@ -2282,7 +2282,7 @@ func (n *ovn) setup(update bool) error { } if len(deleteDHCPRecords) > 0 { - err = client.LogicalSwitchDHCPOptionsDelete(n.getIntSwitchName(), deleteDHCPRecords...) + err = ovnnb.LogicalSwitchDHCPOptionsDelete(n.getIntSwitchName(), deleteDHCPRecords...) if err != nil { return fmt.Errorf("Failed deleting existing DHCP settings for internal switch: %w", err) } @@ -2297,7 +2297,7 @@ func (n *ovn) setup(update bool) error { dhcpV4Netmask = "255.255.255.255" } - err = client.LogicalSwitchDHCPv4OptionsSet(n.getIntSwitchName(), dhcpv4UUID, dhcpV4Subnet, &networkOVN.OVNDHCPv4Opts{ + err = ovnnb.LogicalSwitchDHCPv4OptionsSet(n.getIntSwitchName(), dhcpv4UUID, dhcpV4Subnet, &networkOVN.OVNDHCPv4Opts{ ServerID: routerIntPortIPv4, ServerMAC: routerMAC, Router: routerIntPortIPv4, @@ -2314,7 +2314,7 @@ func (n *ovn) setup(update bool) error { // Create DHCPv6 options for internal switch. if dhcpV6Subnet != nil { - err = client.LogicalSwitchDHCPv6OptionsSet(n.getIntSwitchName(), dhcpv6UUID, dhcpV6Subnet, &networkOVN.OVNDHCPv6Opts{ + err = ovnnb.LogicalSwitchDHCPv6OptionsSet(n.getIntSwitchName(), dhcpv6UUID, dhcpV6Subnet, &networkOVN.OVNDHCPv6Opts{ ServerID: routerMAC, RecursiveDNSServer: uplinkNet.dnsIPv6, DNSSearchList: n.getDNSSearchList(), @@ -2339,7 +2339,7 @@ func (n *ovn) setup(update bool) error { recursiveDNSServer = uplinkNet.dnsIPv6[0] // OVN only supports 1 RA DNS server. } - err = client.LogicalRouterPortSetIPv6Advertisements(n.getRouterIntPortName(), &networkOVN.OVNIPv6RAOpts{ + err = ovnnb.LogicalRouterPortSetIPv6Advertisements(n.getRouterIntPortName(), &networkOVN.OVNIPv6RAOpts{ AddressMode: adressMode, SendPeriodic: true, DNSSearchList: n.getDNSSearchList(), @@ -2355,29 +2355,29 @@ func (n *ovn) setup(update bool) error { return fmt.Errorf("Failed setting internal router port IPv6 advertisement settings: %w", err) } } else { - err = client.LogicalRouterPortDeleteIPv6Advertisements(n.getRouterIntPortName()) + err = ovnnb.LogicalRouterPortDeleteIPv6Advertisements(n.getRouterIntPortName()) if err != nil { return fmt.Errorf("Failed removing internal router port IPv6 advertisement settings: %w", err) } } // Create internal switch port and link to router port. - err = client.LogicalSwitchPortAdd(n.getIntSwitchName(), n.getIntSwitchRouterPortName(), nil, update) + err = ovnnb.LogicalSwitchPortAdd(n.getIntSwitchName(), n.getIntSwitchRouterPortName(), nil, update) if err != nil { return fmt.Errorf("Failed adding internal switch router port: %w", err) } if !update { - revert.Add(func() { _ = client.LogicalSwitchPortDelete(n.getIntSwitchRouterPortName()) }) + revert.Add(func() { _ = ovnnb.LogicalSwitchPortDelete(n.getIntSwitchRouterPortName()) }) } - err = client.LogicalSwitchPortLinkRouter(n.getIntSwitchRouterPortName(), n.getRouterIntPortName()) + err = ovnnb.LogicalSwitchPortLinkRouter(n.getIntSwitchRouterPortName(), n.getRouterIntPortName()) if err != nil { return fmt.Errorf("Failed linking internal router port to internal switch port: %w", err) } // Apply baseline ACL rules to internal logical switch. - err = acl.OVNApplyNetworkBaselineRules(client, n.getIntSwitchName(), n.getIntSwitchRouterPortName(), intRouterIPs, append(uplinkNet.dnsIPv4, uplinkNet.dnsIPv6...)) + err = acl.OVNApplyNetworkBaselineRules(ovnnb, n.getIntSwitchName(), n.getIntSwitchRouterPortName(), intRouterIPs, append(uplinkNet.dnsIPv4, uplinkNet.dnsIPv6...)) if err != nil { return fmt.Errorf("Failed applying baseline ACL rules to internal switch: %w", err) } @@ -2402,7 +2402,7 @@ func (n *ovn) setup(update bool) error { n.Name(): {Name: n.Name(), Type: n.Type(), ID: n.ID(), Config: n.Config()}, } - cleanup, err := acl.OVNEnsureACLs(n.state, n.logger, client, n.Project(), aclNameIDs, aclNets, securityACLS, false) + cleanup, err := acl.OVNEnsureACLs(n.state, n.logger, ovnnb, n.Project(), aclNameIDs, aclNets, securityACLS, false) if err != nil { return fmt.Errorf("Failed ensuring security ACLs are configured in OVN for network: %w", err) } @@ -2418,7 +2418,7 @@ func (n *ovn) setup(update bool) error { // Optionally excludePeers takes a list of peer network IDs to exclude from the router policy. This is useful // when removing a peer connection as it allows the security policy to be removed from OVN for that peer before the // peer connection has been removed from the database. -func (n *ovn) logicalRouterPolicySetup(client *networkOVN.OVN, excludePeers ...int64) error { +func (n *ovn) logicalRouterPolicySetup(ovnnb *networkOVN.OVN, excludePeers ...int64) error { extRouterPort := n.getRouterExtPortName() intRouterPort := n.getRouterIntPortName() addrSetPrefix := acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID()) @@ -2475,20 +2475,20 @@ func (n *ovn) logicalRouterPolicySetup(client *networkOVN.OVN, excludePeers ...i return err } - return client.LogicalRouterPolicyApply(n.getRouterName(), policies...) + return ovnnb.LogicalRouterPolicyApply(n.getRouterName(), policies...) } // ensureNetworkPortGroup ensures that the network level port group (used for classifying NICs connected to this // network as internal) exists. func (n *ovn) ensureNetworkPortGroup(projectID int64) error { - client, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } // Create port group (if needed) for NICs to classify as internal. intPortGroupName := acl.OVNIntSwitchPortGroupName(n.ID()) - intPortGroupUUID, _, err := client.PortGroupInfo(intPortGroupName) + intPortGroupUUID, _, err := ovnnb.PortGroupInfo(intPortGroupName) if err != nil { return fmt.Errorf("Failed getting port group UUID for network %q setup: %w", n.Name(), err) } @@ -2496,7 +2496,7 @@ func (n *ovn) ensureNetworkPortGroup(projectID int64) error { if intPortGroupUUID == "" { // Create internal port group and associate it with the logical switch, so that it will be // removed when the logical switch is removed. - err = client.PortGroupAdd(projectID, intPortGroupName, "", n.getIntSwitchName()) + err = ovnnb.PortGroupAdd(projectID, intPortGroupName, "", n.getIntSwitchName()) if err != nil { return fmt.Errorf("Failed creating port group %q for network %q setup: %w", intPortGroupName, n.Name(), err) } @@ -2509,14 +2509,14 @@ func (n *ovn) ensureNetworkPortGroup(projectID int64) error { // The chassis priority value is a stable-random value derived from chassis group name and node ID. This is so we // don't end up using the same chassis for the primary uplink chassis for all OVN networks in a cluster. func (n *ovn) addChassisGroupEntry() error { - client, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } // Get local chassis ID for chassis group. - ovs := ovs.NewOVS() - chassisID, err := ovs.ChassisID() + vswitch := ovs.NewOVS() + chassisID, err := vswitch.ChassisID() if err != nil { return fmt.Errorf("Failed getting OVS Chassis ID: %w", err) } @@ -2562,7 +2562,7 @@ func (n *ovn) addChassisGroupEntry() error { } } - err = client.ChassisGroupChassisAdd(chassisGroupName, chassisID, priority) + err = ovnnb.ChassisGroupChassisAdd(chassisGroupName, chassisID, priority) if err != nil { return fmt.Errorf("Failed adding OVS chassis %q with priority %d to chassis group %q: %w", chassisID, priority, chassisGroupName, err) } @@ -2574,19 +2574,19 @@ func (n *ovn) addChassisGroupEntry() error { // deleteChassisGroupEntry deletes an entry for the local OVS chassis from the OVN logical network's chassis group. func (n *ovn) deleteChassisGroupEntry() error { - client, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } // Remove local chassis from chassis group. - ovs := ovs.NewOVS() - chassisID, err := ovs.ChassisID() + vswitch := ovs.NewOVS() + chassisID, err := vswitch.ChassisID() if err != nil { return fmt.Errorf("Failed getting OVS Chassis ID: %w", err) } - err = client.ChassisGroupChassisDelete(n.getChassisGroupName(), chassisID) + err = ovnnb.ChassisGroupChassisDelete(n.getChassisGroupName(), chassisID) if err != nil { return fmt.Errorf("Failed deleting OVS chassis %q from chassis group %q: %w", chassisID, n.getChassisGroupName(), err) } @@ -2604,58 +2604,58 @@ func (n *ovn) Delete(clientType request.ClientType) error { } if clientType == request.ClientTypeNormal { - client, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } - err = client.LogicalRouterDelete(n.getRouterName()) + err = ovnnb.LogicalRouterDelete(n.getRouterName()) if err != nil { return err } - err = client.LogicalSwitchDelete(n.getExtSwitchName()) + err = ovnnb.LogicalSwitchDelete(n.getExtSwitchName()) if err != nil { return err } - err = client.LogicalSwitchDelete(n.getIntSwitchName()) + err = ovnnb.LogicalSwitchDelete(n.getIntSwitchName()) if err != nil { return err } - err = client.AddressSetDelete(acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID())) + err = ovnnb.AddressSetDelete(acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID())) if err != nil { return err } - err = client.LogicalRouterPortDelete(n.getRouterExtPortName()) + err = ovnnb.LogicalRouterPortDelete(n.getRouterExtPortName()) if err != nil { return err } - err = client.LogicalRouterPortDelete(n.getRouterIntPortName()) + err = ovnnb.LogicalRouterPortDelete(n.getRouterIntPortName()) if err != nil { return err } - err = client.LogicalSwitchPortDelete(n.getExtSwitchRouterPortName()) + err = ovnnb.LogicalSwitchPortDelete(n.getExtSwitchRouterPortName()) if err != nil { return err } - err = client.LogicalSwitchPortDelete(n.getExtSwitchProviderPortName()) + err = ovnnb.LogicalSwitchPortDelete(n.getExtSwitchProviderPortName()) if err != nil { return err } - err = client.LogicalSwitchPortDelete(n.getIntSwitchRouterPortName()) + err = ovnnb.LogicalSwitchPortDelete(n.getIntSwitchRouterPortName()) if err != nil { return err } // Must be done after logical router removal. - err = client.ChassisGroupDelete(n.getChassisGroupName()) + err = ovnnb.ChassisGroupDelete(n.getChassisGroupName()) if err != nil { return err } @@ -2663,7 +2663,7 @@ func (n *ovn) Delete(clientType request.ClientType) error { // Check for port groups that will become unused (and need deleting) as this network is deleted. securityACLs := util.SplitNTrimSpace(n.config["security.acls"], ",", -1, true) if len(securityACLs) > 0 { - err = acl.OVNPortGroupDeleteIfUnused(n.state, n.logger, client, n.project, &api.Network{Name: n.name}, "") + err = acl.OVNPortGroupDeleteIfUnused(n.state, n.logger, ovnnb, n.project, &api.Network{Name: n.name}, "") if err != nil { return fmt.Errorf("Failed removing unused OVN port groups: %w", err) } @@ -2690,7 +2690,7 @@ func (n *ovn) Delete(clientType request.ClientType) error { loadBalancers = append(loadBalancers, n.getLoadBalancerName(listenAddress)) } - err = client.LoadBalancerDelete(loadBalancers...) + err = ovnnb.LoadBalancerDelete(loadBalancers...) if err != nil { return fmt.Errorf("Failed deleting network forwards and load balancers: %w", err) } @@ -2978,13 +2978,13 @@ func (n *ovn) Update(newNetwork api.NetworkPut, targetNode string, clientType re addChangeSet := map[networkOVN.OVNPortGroup][]networkOVN.OVNSwitchPortUUID{} removeChangeSet := map[networkOVN.OVNPortGroup][]networkOVN.OVNSwitchPortUUID{} - client, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } // Get list of active switch ports (avoids repeated querying of OVN NB). - activePorts, err := client.LogicalSwitchPorts(n.getIntSwitchName()) + activePorts, err := ovnnb.LogicalSwitchPorts(n.getIntSwitchName()) if err != nil { return fmt.Errorf("Failed getting active ports: %w", err) } @@ -3044,7 +3044,7 @@ func (n *ovn) Update(newNetwork api.NetworkPut, targetNode string, clientType re // If there are no ACLs being applied to the NIC (either from network or NIC) then // we should remove the default rule from the NIC. if len(newACLs) <= 0 && len(nicACLs) <= 0 { - err = client.PortGroupPortClearACLRules(acl.OVNIntSwitchPortGroupName(n.ID()), instancePortName) + err = ovnnb.PortGroupPortClearACLRules(acl.OVNIntSwitchPortGroupName(n.ID()), instancePortName) if err != nil { return fmt.Errorf("Failed clearing OVN default ACL rules for instance NIC: %w", err) } @@ -3074,7 +3074,7 @@ func (n *ovn) Update(newNetwork api.NetworkPut, targetNode string, clientType re egressAction, egressLogged := n.instanceDeviceACLDefaults(nicConfig, "egress") logPrefix := fmt.Sprintf("%s-%s", inst.Config["volatile.uuid"], nicName) - err = acl.OVNApplyInstanceNICDefaultRules(client, acl.OVNIntSwitchPortGroupName(n.ID()), logPrefix, instancePortName, ingressAction, ingressLogged, egressAction, egressLogged) + err = acl.OVNApplyInstanceNICDefaultRules(ovnnb, acl.OVNIntSwitchPortGroupName(n.ID()), logPrefix, instancePortName, ingressAction, ingressLogged, egressAction, egressLogged) if err != nil { return fmt.Errorf("Failed applying OVN default ACL rules for instance NIC: %w", err) } @@ -3096,7 +3096,7 @@ func (n *ovn) Update(newNetwork api.NetworkPut, targetNode string, clientType re // Apply add/remove changesets. if len(addChangeSet) > 0 || len(removeChangeSet) > 0 { n.logger.Debug("Applying ACL port group member change sets") - err = client.PortGroupMemberChange(addChangeSet, removeChangeSet) + err = ovnnb.PortGroupMemberChange(addChangeSet, removeChangeSet) if err != nil { return fmt.Errorf("Failed applying OVN port group member change sets for instance NIC: %w", err) } @@ -3104,14 +3104,14 @@ func (n *ovn) Update(newNetwork api.NetworkPut, targetNode string, clientType re // Check if any of the removed ACLs should have any unused port groups deleted. if len(removedACLs) > 0 { - err = acl.OVNPortGroupDeleteIfUnused(n.state, n.logger, client, n.project, &api.Network{Name: n.name}, "", newACLs...) + err = acl.OVNPortGroupDeleteIfUnused(n.state, n.logger, ovnnb, n.project, &api.Network{Name: n.name}, "", newACLs...) if err != nil { return fmt.Errorf("Failed removing unused OVN port groups: %w", err) } } // Ensure all active NIC routes are present in internal switch's address set. - err = client.AddressSetAdd(acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID()), localNICRoutes...) + err = ovnnb.AddressSetAdd(acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID()), localNICRoutes...) if err != nil { return fmt.Errorf("Failed adding active NIC routes to switch address set: %w", err) } @@ -3123,7 +3123,7 @@ func (n *ovn) Update(newNetwork api.NetworkPut, targetNode string, clientType re rebuildPeers = true _, oldRouterIntPortIPNet, _ := net.ParseCIDR(oldNetwork.Config[key]) if oldRouterIntPortIPNet != nil { - err = client.AddressSetRemove(acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID()), *oldRouterIntPortIPNet) + err = ovnnb.AddressSetRemove(acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID()), *oldRouterIntPortIPNet) if err != nil { return fmt.Errorf("Failed removing old network subnet %q from switch address set: %w", oldRouterIntPortIPNet.String(), err) } @@ -3139,7 +3139,7 @@ func (n *ovn) Update(newNetwork api.NetworkPut, targetNode string, clientType re } err = n.forPeers(func(targetOVNNet *ovn) error { - err = n.peerSetup(client, targetOVNNet, *opts) + err = n.peerSetup(ovnnb, targetOVNNet, *opts) if err != nil { return err } @@ -3320,30 +3320,30 @@ func (n *ovn) InstanceDevicePortAdd(instanceUUID string, deviceName string, devi revert := revert.New() defer revert.Fail() - client, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } - dnsUUID, err := client.LogicalSwitchPortSetDNS(n.getIntSwitchName(), instancePortName, "", nil) + dnsUUID, err := ovnnb.LogicalSwitchPortSetDNS(n.getIntSwitchName(), instancePortName, "", nil) if err != nil { return fmt.Errorf("Failed adding DNS record: %w", err) } - revert.Add(func() { _ = client.LogicalSwitchPortDeleteDNS(n.getIntSwitchName(), dnsUUID, true) }) + revert.Add(func() { _ = ovnnb.LogicalSwitchPortDeleteDNS(n.getIntSwitchName(), dnsUUID, true) }) // If NIC has static IPv4 address then create a DHCPv4 reservation. if deviceConfig["ipv4.address"] != "" { ip := net.ParseIP(deviceConfig["ipv4.address"]) if ip != nil { - dhcpReservations, err := client.LogicalSwitchDHCPv4RevervationsGet(n.getIntSwitchName()) + dhcpReservations, err := ovnnb.LogicalSwitchDHCPv4RevervationsGet(n.getIntSwitchName()) if err != nil { return fmt.Errorf("Failed getting DHCPv4 reservations: %w", err) } if !n.hasDHCPv4Reservation(dhcpReservations, ip) { dhcpReservations = append(dhcpReservations, iprange.Range{Start: ip}) - err = client.LogicalSwitchDHCPv4RevervationsSet(n.getIntSwitchName(), dhcpReservations) + err = ovnnb.LogicalSwitchDHCPv4RevervationsSet(n.getIntSwitchName(), dhcpReservations) if err != nil { return fmt.Errorf("Failed adding DHCPv4 reservation for %q: %w", ip.String(), err) } @@ -3401,7 +3401,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL revert := revert.New() defer revert.Fail() - client, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewOVN(n.state) if err != nil { return "", nil, fmt.Errorf("Failed to get OVN client: %w", err) } @@ -3409,7 +3409,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL // Get existing DHCPv4 static reservations. // This is used for both checking sticky DHCPv4 allocation availability and for ensuring static DHCP // reservations exist. - dhcpReservations, err := client.LogicalSwitchDHCPv4RevervationsGet(n.getIntSwitchName()) + dhcpReservations, err := ovnnb.LogicalSwitchDHCPv4RevervationsGet(n.getIntSwitchName()) if err != nil { return "", nil, fmt.Errorf("Failed getting DHCPv4 reservations: %w", err) } @@ -3420,7 +3420,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL if dhcpv4Subnet != nil || dhcpv6Subnet != nil { // Find existing DHCP options set for IPv4 and IPv6 and update them instead of adding sets. - existingOpts, err := client.LogicalSwitchDHCPOptionsGet(n.getIntSwitchName()) + existingOpts, err := ovnnb.LogicalSwitchDHCPOptionsGet(n.getIntSwitchName()) if err != nil { return "", nil, fmt.Errorf("Failed getting existing DHCP settings for internal switch: %w", err) } @@ -3457,7 +3457,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL // If the sticky IP isn't statically reserved, lets check its not used dynamically // on any active port. if !n.hasDHCPv4Reservation(dhcpReservations, dhcpV4StickyIP) { - existingPortIPs, err := client.LogicalSwitchIPs(n.getIntSwitchName()) + existingPortIPs, err := ovnnb.LogicalSwitchIPs(n.getIntSwitchName()) if err != nil { return "", nil, fmt.Errorf("Failed getting existing switch port IPs: %w", err) } @@ -3538,7 +3538,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL // to configure the port as needed. This is required in case the OVN northbound database was unavailable // when the instance NIC was stopped and was unable to remove the port on last stop, which would otherwise // prevent future NIC starts. - err = client.LogicalSwitchPortAdd(n.getIntSwitchName(), instancePortName, &networkOVN.OVNSwitchPortOpts{ + err = ovnnb.LogicalSwitchPortAdd(n.getIntSwitchName(), instancePortName, &networkOVN.OVNSwitchPortOpts{ DHCPv4OptsID: dhcpV4ID, DHCPv6OptsID: dhcpv6ID, MAC: mac, @@ -3551,7 +3551,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL return "", nil, err } - revert.Add(func() { _ = client.LogicalSwitchPortDelete(instancePortName) }) + revert.Add(func() { _ = ovnnb.LogicalSwitchPortDelete(instancePortName) }) // Add DNS records for port's IPs, and retrieve the IP addresses used. var dnsIPv4, dnsIPv6 net.IP @@ -3583,7 +3583,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL // Retry a few times in case port has not yet allocated dynamic IPs. for i := 0; i < 5; i++ { - dynamicIPs, err = client.LogicalSwitchPortDynamicIPs(instancePortName) + dynamicIPs, err = ovnnb.LogicalSwitchPortDynamicIPs(instancePortName) if err != nil { return "", nil, err } @@ -3607,12 +3607,12 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL } dnsName := fmt.Sprintf("%s.%s", opts.DNSName, n.getDomainName()) - dnsUUID, err := client.LogicalSwitchPortSetDNS(n.getIntSwitchName(), instancePortName, dnsName, dnsIPs) + dnsUUID, err := ovnnb.LogicalSwitchPortSetDNS(n.getIntSwitchName(), instancePortName, dnsName, dnsIPs) if err != nil { return "", nil, fmt.Errorf("Failed setting DNS for %q: %w", dnsName, err) } - revert.Add(func() { _ = client.LogicalSwitchPortDeleteDNS(n.getIntSwitchName(), dnsUUID, false) }) + revert.Add(func() { _ = ovnnb.LogicalSwitchPortDeleteDNS(n.getIntSwitchName(), dnsUUID, false) }) // If NIC has static IPv4 address then ensure a DHCPv4 reservation exists. // Do this at start time as well as add time in case an instance was copied (causing a duplicate address @@ -3621,7 +3621,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL if opts.DeviceConfig["ipv4.address"] != "" && dnsIPv4 != nil { if !n.hasDHCPv4Reservation(dhcpReservations, dnsIPv4) { dhcpReservations = append(dhcpReservations, iprange.Range{Start: dnsIPv4}) - err = client.LogicalSwitchDHCPv4RevervationsSet(n.getIntSwitchName(), dhcpReservations) + err = ovnnb.LogicalSwitchDHCPv4RevervationsSet(n.getIntSwitchName(), dhcpReservations) if err != nil { return "", nil, fmt.Errorf("Failed adding DHCPv4 reservation for %q: %w", dnsIPv4.String(), err) } @@ -3647,12 +3647,12 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL continue // No qualifying target IP from DNS records. } - err = client.LogicalRouterDNATSNATAdd(n.getRouterName(), ip, ip, true, true) + err = ovnnb.LogicalRouterDNATSNATAdd(n.getRouterName(), ip, ip, true, true) if err != nil { return "", nil, err } - revert.Add(func() { _ = client.LogicalRouterDNATSNATDelete(n.getRouterName(), ip) }) + revert.Add(func() { _ = ovnnb.LogicalRouterDNATSNATDelete(n.getRouterName(), ip) }) } } @@ -3711,12 +3711,12 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL // DNAT doesn't support whole subnets. if util.ValueInSlice(opts.UplinkConfig["ovn.ingress_mode"], []string{"l2proxy", ""}) { err = SubnetIterate(externalRoute, func(ip net.IP) error { - err = client.LogicalRouterDNATSNATAdd(n.getRouterName(), ip, ip, true, true) + err = ovnnb.LogicalRouterDNATSNATAdd(n.getRouterName(), ip, ip, true, true) if err != nil { return err } - revert.Add(func() { _ = client.LogicalRouterDNATSNATDelete(n.getRouterName(), ip) }) + revert.Add(func() { _ = ovnnb.LogicalRouterDNATSNATDelete(n.getRouterName(), ip) }) return nil }) @@ -3728,7 +3728,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL if len(routes) > 0 { // Add routes to local router. - err = client.LogicalRouterRouteAdd(n.getRouterName(), true, routes...) + err = ovnnb.LogicalRouterRouteAdd(n.getRouterName(), true, routes...) if err != nil { return "", nil, err } @@ -3738,16 +3738,16 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL routePrefixes = append(routePrefixes, route.Prefix) } - revert.Add(func() { _ = client.LogicalRouterRouteDelete(n.getRouterName(), routePrefixes...) }) + revert.Add(func() { _ = ovnnb.LogicalRouterRouteDelete(n.getRouterName(), routePrefixes...) }) // Add routes to internal switch's address set for ACL usage. - err = client.AddressSetAdd(acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID()), routePrefixes...) + err = ovnnb.AddressSetAdd(acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID()), routePrefixes...) if err != nil { return "", nil, fmt.Errorf("Failed adding switch address set entries: %w", err) } revert.Add(func() { - _ = client.AddressSetRemove(acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID()), routePrefixes...) + _ = ovnnb.AddressSetRemove(acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID()), routePrefixes...) }) routerIntPortIPv4, _, err := n.parseRouterIntPortIPv4Net() @@ -3782,12 +3782,12 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL }) } - err = client.LogicalRouterRouteAdd(targetRouterName, true, targetRouterRoutes...) + err = ovnnb.LogicalRouterRouteAdd(targetRouterName, true, targetRouterRoutes...) if err != nil { return fmt.Errorf("Failed adding static routes to peer network %q in project %q: %w", targetOVNNet.Name(), targetOVNNet.Project(), err) } - revert.Add(func() { _ = client.LogicalRouterRouteDelete(targetRouterName, routePrefixes...) }) + revert.Add(func() { _ = ovnnb.LogicalRouterRouteDelete(targetRouterName, routePrefixes...) }) return nil }) @@ -3811,7 +3811,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL removeChangeSet := map[networkOVN.OVNPortGroup][]networkOVN.OVNSwitchPortUUID{} // Get logical port UUID. - portUUID, err := client.LogicalSwitchPortUUID(instancePortName) + portUUID, err := ovnnb.LogicalSwitchPortUUID(instancePortName) if err != nil || portUUID == "" { return "", nil, fmt.Errorf("Failed getting logical port UUID for security ACL removal: %w", err) } @@ -3834,7 +3834,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL n.Name(): {Name: n.Name(), Type: n.Type(), ID: n.ID(), Config: n.Config()}, } - cleanup, err := acl.OVNEnsureACLs(n.state, n.logger, client, n.Project(), aclNameIDs, aclNets, nicACLNames, false) + cleanup, err := acl.OVNEnsureACLs(n.state, n.logger, ovnnb, n.Project(), aclNameIDs, aclNets, nicACLNames, false) if err != nil { return "", nil, fmt.Errorf("Failed ensuring security ACLs are configured in OVN for instance: %w", err) } @@ -3878,7 +3878,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL // be populated even if no ACLs being applied, because the NIC port needs to be added to the network level // port group. n.logger.Debug("Applying instance NIC port group member change sets") - err = client.PortGroupMemberChange(addChangeSet, removeChangeSet) + err = ovnnb.PortGroupMemberChange(addChangeSet, removeChangeSet) if err != nil { return "", nil, fmt.Errorf("Failed applying OVN port group member change sets for instance NIC: %w", err) } @@ -3889,14 +3889,14 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL egressAction, egressLogged := n.instanceDeviceACLDefaults(opts.DeviceConfig, "egress") logPrefix := fmt.Sprintf("%s-%s", opts.InstanceUUID, opts.DeviceName) - err = acl.OVNApplyInstanceNICDefaultRules(client, acl.OVNIntSwitchPortGroupName(n.ID()), logPrefix, instancePortName, ingressAction, ingressLogged, egressAction, egressLogged) + err = acl.OVNApplyInstanceNICDefaultRules(ovnnb, acl.OVNIntSwitchPortGroupName(n.ID()), logPrefix, instancePortName, ingressAction, ingressLogged, egressAction, egressLogged) if err != nil { return "", nil, fmt.Errorf("Failed applying OVN default ACL rules for instance NIC: %w", err) } n.logger.Debug("Set NIC default rule", logger.Ctx{"port": instancePortName, "ingressAction": ingressAction, "ingressLogged": ingressLogged, "egressAction": egressAction, "egressLogged": egressLogged}) } else { - err = client.PortGroupPortClearACLRules(acl.OVNIntSwitchPortGroupName(n.ID()), instancePortName) + err = ovnnb.PortGroupPortClearACLRules(acl.OVNIntSwitchPortGroupName(n.ID()), instancePortName) if err != nil { return "", nil, fmt.Errorf("Failed clearing OVN default ACL rules for instance NIC: %w", err) } @@ -3935,14 +3935,14 @@ func (n *ovn) InstanceDevicePortIPs(instanceUUID string, deviceName string) ([]n return nil, fmt.Errorf("Instance UUID is required") } - client, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewOVN(n.state) if err != nil { return nil, fmt.Errorf("Failed to get OVN client: %w", err) } instancePortName := n.getInstanceDevicePortName(instanceUUID, deviceName) - devIPs, err := client.LogicalSwitchPortIPs(instancePortName) + devIPs, err := ovnnb.LogicalSwitchPortIPs(instancePortName) if err != nil { return nil, fmt.Errorf("Failed to get OVN switch port IPs: %w", err) } @@ -3964,12 +3964,12 @@ func (n *ovn) InstanceDevicePortStop(ovsExternalOVNPort networkOVN.OVNSwitchPort source = "internal" } - client, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } - portLocation, err := client.LogicalSwitchPortLocationGet(instancePortName) + portLocation, err := ovnnb.LogicalSwitchPortLocationGet(instancePortName) if err != nil { return fmt.Errorf("Failed getting instance switch port options: %w", err) } @@ -3993,13 +3993,13 @@ func (n *ovn) InstanceDevicePortStop(ovsExternalOVNPort networkOVN.OVNSwitchPort } // Get DNS records. - dnsUUID, _, dnsIPs, err := client.LogicalSwitchPortGetDNS(instancePortName) + dnsUUID, _, dnsIPs, err := ovnnb.LogicalSwitchPortGetDNS(instancePortName) if err != nil { return err } // Cleanup logical switch port and associated config. - err = client.LogicalSwitchPortCleanup(instancePortName, n.getIntSwitchName(), acl.OVNIntSwitchPortGroupName(n.ID()), dnsUUID) + err = ovnnb.LogicalSwitchPortCleanup(instancePortName, n.getIntSwitchName(), acl.OVNIntSwitchPortGroupName(n.ID()), dnsUUID) if err != nil { return err } @@ -4044,13 +4044,13 @@ func (n *ovn) InstanceDevicePortStop(ovsExternalOVNPort networkOVN.OVNSwitchPort if len(removeRoutes) > 0 { // Delete routes from local router. - err = client.LogicalRouterRouteDelete(n.getRouterName(), removeRoutes...) + err = ovnnb.LogicalRouterRouteDelete(n.getRouterName(), removeRoutes...) if err != nil { return err } // Delete routes from switch address set. - err = client.AddressSetRemove(acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID()), removeRoutes...) + err = ovnnb.AddressSetRemove(acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID()), removeRoutes...) if err != nil { return fmt.Errorf("Failed deleting switch address set entries: %w", err) } @@ -4058,7 +4058,7 @@ func (n *ovn) InstanceDevicePortStop(ovsExternalOVNPort networkOVN.OVNSwitchPort // Delete routes from peer routers. err = n.forPeers(func(targetOVNNet *ovn) error { targetRouterName := targetOVNNet.getRouterName() - err = client.LogicalRouterRouteDelete(targetRouterName, removeRoutes...) + err = ovnnb.LogicalRouterRouteDelete(targetRouterName, removeRoutes...) if err != nil { return fmt.Errorf("Failed deleting static routes from peer network %q in project %q: %w", targetOVNNet.Name(), targetOVNNet.Project(), err) } @@ -4071,7 +4071,7 @@ func (n *ovn) InstanceDevicePortStop(ovsExternalOVNPort networkOVN.OVNSwitchPort } if len(removeNATIPs) > 0 { - err = client.LogicalRouterDNATSNATDelete(n.getRouterName(), removeNATIPs...) + err = ovnnb.LogicalRouterDNATSNATDelete(n.getRouterName(), removeNATIPs...) if err != nil { return err } @@ -4089,13 +4089,13 @@ func (n *ovn) InstanceDevicePortRemove(instanceUUID string, deviceName string, d revert := revert.New() defer revert.Fail() - client, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } // Get DNS records. - dnsUUID, _, _, err := client.LogicalSwitchPortGetDNS(instancePortName) + dnsUUID, _, _, err := ovnnb.LogicalSwitchPortGetDNS(instancePortName) if err != nil { return err } @@ -4106,7 +4106,7 @@ func (n *ovn) InstanceDevicePortRemove(instanceUUID string, deviceName string, d if deviceConfig["ipv4.address"] != "" { ip := net.ParseIP(deviceConfig["ipv4.address"]) if ip != nil { - dhcpReservations, err := client.LogicalSwitchDHCPv4RevervationsGet(n.getIntSwitchName()) + dhcpReservations, err := ovnnb.LogicalSwitchDHCPv4RevervationsGet(n.getIntSwitchName()) if err != nil { return fmt.Errorf("Failed getting DHCPv4 reservations: %w", err) } @@ -4125,7 +4125,7 @@ func (n *ovn) InstanceDevicePortRemove(instanceUUID string, deviceName string, d } if found { - err = client.LogicalSwitchDHCPv4RevervationsSet(n.getIntSwitchName(), dhcpReservationsNew) + err = ovnnb.LogicalSwitchDHCPv4RevervationsSet(n.getIntSwitchName(), dhcpReservationsNew) if err != nil { return fmt.Errorf("Failed removing DHCPv4 reservation for %q: %w", ip.String(), err) } @@ -4133,7 +4133,7 @@ func (n *ovn) InstanceDevicePortRemove(instanceUUID string, deviceName string, d } } - err = client.LogicalSwitchPortDeleteDNS(n.getIntSwitchName(), dnsUUID, true) + err = ovnnb.LogicalSwitchPortDeleteDNS(n.getIntSwitchName(), dnsUUID, true) if err != nil { return fmt.Errorf("Failed deleting DNS record: %w", err) } @@ -4342,14 +4342,14 @@ func (n *ovn) handleDependencyChange(uplinkName string, uplinkConfig map[string] if util.ValueInSlice("ovn.ingress_mode", changedKeys) { n.logger.Debug("Applying ingress mode changes from uplink network to instance NICs", logger.Ctx{"uplink": uplinkName}) - client, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } if util.ValueInSlice(uplinkConfig["ovn.ingress_mode"], []string{"l2proxy", ""}) { // Get list of active switch ports (avoids repeated querying of OVN NB). - activePorts, err := client.LogicalSwitchPorts(n.getIntSwitchName()) + activePorts, err := ovnnb.LogicalSwitchPorts(n.getIntSwitchName()) if err != nil { return fmt.Errorf("Failed getting active ports: %w", err) } @@ -4411,7 +4411,7 @@ func (n *ovn) handleDependencyChange(uplinkName string, uplinkConfig map[string] } else { // Remove all DNAT_AND_SNAT rules if not using l2proxy ingress mode, as currently we only // use DNAT_AND_SNAT rules for this feature so it is safe to do. - err = client.LogicalRouterDNATSNATDeleteAll(n.getRouterName()) + err = ovnnb.LogicalRouterDNATSNATDeleteAll(n.getRouterName()) if err != nil { return fmt.Errorf("Failed deleting instance NIC ingress mode l2proxy rules: %w", err) } @@ -4552,7 +4552,7 @@ func (n *ovn) ForwardCreate(forward api.NetworkForwardsPost, clientType request. } } - client, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -4565,13 +4565,13 @@ func (n *ovn) ForwardCreate(forward api.NetworkForwardsPost, clientType request. revert.Add(func() { _ = n.state.DB.Cluster.DeleteNetworkForward(n.ID(), forwardID) - _ = client.LoadBalancerDelete(n.getLoadBalancerName(forward.ListenAddress)) + _ = ovnnb.LoadBalancerDelete(n.getLoadBalancerName(forward.ListenAddress)) _ = n.forwardBGPSetupPrefixes() }) vips := n.forwardFlattenVIPs(net.ParseIP(forward.ListenAddress), net.ParseIP(forward.Config["target_address"]), portMaps) - err = client.LoadBalancerApply(n.getLoadBalancerName(forward.ListenAddress), []networkOVN.OVNRouter{n.getRouterName()}, []networkOVN.OVNSwitch{n.getIntSwitchName()}, vips...) + err = ovnnb.LoadBalancerApply(n.getLoadBalancerName(forward.ListenAddress), []networkOVN.OVNRouter{n.getRouterName()}, []networkOVN.OVNSwitch{n.getIntSwitchName()}, vips...) if err != nil { return fmt.Errorf("Failed applying OVN load balancer: %w", err) } @@ -4636,13 +4636,13 @@ func (n *ovn) ForwardUpdate(listenAddress string, req api.NetworkForwardPut, cli return nil // Nothing has changed. } - client, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } vips := n.forwardFlattenVIPs(net.ParseIP(newForward.ListenAddress), net.ParseIP(newForward.Config["target_address"]), portMaps) - err = client.LoadBalancerApply(n.getLoadBalancerName(newForward.ListenAddress), []networkOVN.OVNRouter{n.getRouterName()}, []networkOVN.OVNSwitch{n.getIntSwitchName()}, vips...) + err = ovnnb.LoadBalancerApply(n.getLoadBalancerName(newForward.ListenAddress), []networkOVN.OVNRouter{n.getRouterName()}, []networkOVN.OVNSwitch{n.getIntSwitchName()}, vips...) if err != nil { return fmt.Errorf("Failed applying OVN load balancer: %w", err) } @@ -4652,7 +4652,7 @@ func (n *ovn) ForwardUpdate(listenAddress string, req api.NetworkForwardPut, cli portMaps, err := n.forwardValidate(net.ParseIP(curForward.ListenAddress), &curForward.NetworkForwardPut) if err == nil { vips := n.forwardFlattenVIPs(net.ParseIP(curForward.ListenAddress), net.ParseIP(curForward.Config["target_address"]), portMaps) - _ = client.LoadBalancerApply(n.getLoadBalancerName(curForward.ListenAddress), []networkOVN.OVNRouter{n.getRouterName()}, []networkOVN.OVNSwitch{n.getIntSwitchName()}, vips...) + _ = ovnnb.LoadBalancerApply(n.getLoadBalancerName(curForward.ListenAddress), []networkOVN.OVNRouter{n.getRouterName()}, []networkOVN.OVNSwitch{n.getIntSwitchName()}, vips...) _ = n.forwardBGPSetupPrefixes() } }) @@ -4699,12 +4699,12 @@ func (n *ovn) ForwardDelete(listenAddress string, clientType request.ClientType) return err } - client, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } - err = client.LoadBalancerDelete(n.getLoadBalancerName(forward.ListenAddress)) + err = ovnnb.LoadBalancerDelete(n.getLoadBalancerName(forward.ListenAddress)) if err != nil { return fmt.Errorf("Failed deleting OVN load balancer: %w", err) } @@ -4863,7 +4863,7 @@ func (n *ovn) LoadBalancerCreate(loadBalancer api.NetworkLoadBalancersPost, clie } } - client, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -4876,13 +4876,13 @@ func (n *ovn) LoadBalancerCreate(loadBalancer api.NetworkLoadBalancersPost, clie revert.Add(func() { _ = n.state.DB.Cluster.DeleteNetworkLoadBalancer(n.ID(), loadBalancerID) - _ = client.LoadBalancerDelete(n.getLoadBalancerName(loadBalancer.ListenAddress)) + _ = ovnnb.LoadBalancerDelete(n.getLoadBalancerName(loadBalancer.ListenAddress)) _ = n.loadBalancerBGPSetupPrefixes() }) vips := n.loadBalancerFlattenVIPs(net.ParseIP(loadBalancer.ListenAddress), portMaps) - err = client.LoadBalancerApply(n.getLoadBalancerName(loadBalancer.ListenAddress), []networkOVN.OVNRouter{n.getRouterName()}, []networkOVN.OVNSwitch{n.getIntSwitchName()}, vips...) + err = ovnnb.LoadBalancerApply(n.getLoadBalancerName(loadBalancer.ListenAddress), []networkOVN.OVNRouter{n.getRouterName()}, []networkOVN.OVNSwitch{n.getIntSwitchName()}, vips...) if err != nil { return fmt.Errorf("Failed applying OVN load balancer: %w", err) } @@ -4947,14 +4947,14 @@ func (n *ovn) LoadBalancerUpdate(listenAddress string, req api.NetworkLoadBalanc return nil // Nothing has changed. } - client, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } vips := n.loadBalancerFlattenVIPs(net.ParseIP(newLoadBalancer.ListenAddress), portMaps) - err = client.LoadBalancerApply(n.getLoadBalancerName(newLoadBalancer.ListenAddress), []networkOVN.OVNRouter{n.getRouterName()}, []networkOVN.OVNSwitch{n.getIntSwitchName()}, vips...) + err = ovnnb.LoadBalancerApply(n.getLoadBalancerName(newLoadBalancer.ListenAddress), []networkOVN.OVNRouter{n.getRouterName()}, []networkOVN.OVNSwitch{n.getIntSwitchName()}, vips...) if err != nil { return fmt.Errorf("Failed applying OVN load balancer: %w", err) } @@ -4964,7 +4964,7 @@ func (n *ovn) LoadBalancerUpdate(listenAddress string, req api.NetworkLoadBalanc portMaps, err := n.loadBalancerValidate(net.ParseIP(curLoadBalancer.ListenAddress), &curLoadBalancer.NetworkLoadBalancerPut) if err == nil { vips := n.loadBalancerFlattenVIPs(net.ParseIP(curLoadBalancer.ListenAddress), portMaps) - _ = client.LoadBalancerApply(n.getLoadBalancerName(curLoadBalancer.ListenAddress), []networkOVN.OVNRouter{n.getRouterName()}, []networkOVN.OVNSwitch{n.getIntSwitchName()}, vips...) + _ = ovnnb.LoadBalancerApply(n.getLoadBalancerName(curLoadBalancer.ListenAddress), []networkOVN.OVNRouter{n.getRouterName()}, []networkOVN.OVNSwitch{n.getIntSwitchName()}, vips...) _ = n.forwardBGPSetupPrefixes() } }) @@ -5011,12 +5011,12 @@ func (n *ovn) LoadBalancerDelete(listenAddress string, clientType request.Client return err } - client, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } - err = client.LoadBalancerDelete(n.getLoadBalancerName(forward.ListenAddress)) + err = ovnnb.LoadBalancerDelete(n.getLoadBalancerName(forward.ListenAddress)) if err != nil { return fmt.Errorf("Failed deleting OVN load balancer: %w", err) } @@ -5177,19 +5177,19 @@ func (n *ovn) PeerCreate(peer api.NetworkPeersPost) error { return fmt.Errorf("Only peerings in %q state can be setup", api.NetworkStatusCreated) } - client, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } // Apply router security policies. // Should have been done during network setup, but ensure its done here anyway. - err = n.logicalRouterPolicySetup(client) + err = n.logicalRouterPolicySetup(ovnnb) if err != nil { return fmt.Errorf("Failed applying local router security policy: %w", err) } - activeLocalNICPorts, err := client.LogicalSwitchPorts(n.getIntSwitchName()) + activeLocalNICPorts, err := ovnnb.LogicalSwitchPorts(n.getIntSwitchName()) if err != nil { return fmt.Errorf("Failed getting active NIC ports: %w", err) } @@ -5228,12 +5228,12 @@ func (n *ovn) PeerCreate(peer api.NetworkPeersPost) error { } // Ensure local subnets and all active NIC routes are present in internal switch's address set. - err = client.AddressSetAdd(acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID()), opts.TargetRouterRoutes...) + err = ovnnb.AddressSetAdd(acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID()), opts.TargetRouterRoutes...) if err != nil { return fmt.Errorf("Failed adding active NIC routes to switch address set: %w", err) } - err = n.peerSetup(client, targetOVNNet, *opts) + err = n.peerSetup(ovnnb, targetOVNNet, *opts) if err != nil { return err } @@ -5292,7 +5292,7 @@ func (n *ovn) peerGetLocalOpts(localNICRoutes []net.IPNet) (*networkOVN.OVNRoute // peerSetup applies the network peering configuration to both networks. // Accepts an OVN client, a target OVN network, and a set of OVNRouterPeering options pre-filled with local config. -func (n *ovn) peerSetup(client *networkOVN.OVN, targetOVNNet *ovn, opts networkOVN.OVNRouterPeering) error { +func (n *ovn) peerSetup(ovnnb *networkOVN.OVN, targetOVNNet *ovn, opts networkOVN.OVNRouterPeering) error { targetRouterMAC, err := targetOVNNet.getRouterMAC() if err != nil { return fmt.Errorf("Failed getting target router MAC address: %w", err) @@ -5335,7 +5335,7 @@ func (n *ovn) peerSetup(client *networkOVN.OVN, targetOVNNet *ovn, opts networkO } // Get list of active switch ports (avoids repeated querying of OVN NB). - activeTargetNICPorts, err := client.LogicalSwitchPorts(targetOVNNet.getIntSwitchName()) + activeTargetNICPorts, err := ovnnb.LogicalSwitchPorts(targetOVNNet.getIntSwitchName()) if err != nil { return fmt.Errorf("Failed getting active NIC ports: %w", err) } @@ -5357,17 +5357,17 @@ func (n *ovn) peerSetup(client *networkOVN.OVN, targetOVNNet *ovn, opts networkO } // Ensure routes are added to target switch address sets. - err = client.AddressSetAdd(acl.OVNIntSwitchPortGroupAddressSetPrefix(targetOVNNet.ID()), opts.LocalRouterRoutes...) + err = ovnnb.AddressSetAdd(acl.OVNIntSwitchPortGroupAddressSetPrefix(targetOVNNet.ID()), opts.LocalRouterRoutes...) if err != nil { return fmt.Errorf("Failed adding target swith subnet address set entries: %w", err) } - err = targetOVNNet.logicalRouterPolicySetup(client) + err = targetOVNNet.logicalRouterPolicySetup(ovnnb) if err != nil { return fmt.Errorf("Failed applying target router security policy: %w", err) } - err = client.LogicalRouterPeeringApply(opts) + err = ovnnb.LogicalRouterPeeringApply(opts) if err != nil { return fmt.Errorf("Failed applying OVN network peering: %w", err) } @@ -5452,22 +5452,22 @@ func (n *ovn) PeerDelete(peerName string) error { TargetRouterPort: targetOVNNet.getLogicalRouterPeerPortName(n.ID()), } - client, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewOVN(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } - err = client.LogicalRouterPeeringDelete(opts) + err = ovnnb.LogicalRouterPeeringDelete(opts) if err != nil { return fmt.Errorf("Failed deleting OVN network peering: %w", err) } - err = n.logicalRouterPolicySetup(client, targetOVNNet.ID()) + err = n.logicalRouterPolicySetup(ovnnb, targetOVNNet.ID()) if err != nil { return fmt.Errorf("Failed applying local router security policy: %w", err) } - err = targetOVNNet.logicalRouterPolicySetup(client, n.ID()) + err = targetOVNNet.logicalRouterPolicySetup(ovnnb, n.ID()) if err != nil { return fmt.Errorf("Failed applying target router security policy: %w", err) } diff --git a/internal/server/network/network_utils_bridge.go b/internal/server/network/network_utils_bridge.go index e0bb5a4fc0a..cb69d8a6648 100644 --- a/internal/server/network/network_utils_bridge.go +++ b/internal/server/network/network_utils_bridge.go @@ -64,8 +64,8 @@ func AttachInterface(bridgeName string, devName string) error { return err } } else { - ovs := ovs.NewOVS() - err := ovs.BridgePortAdd(bridgeName, devName, true) + vswitch := ovs.NewOVS() + err := vswitch.BridgePortAdd(bridgeName, devName, true) if err != nil { return err } @@ -83,8 +83,8 @@ func DetachInterface(bridgeName string, devName string) error { return err } } else { - ovs := ovs.NewOVS() - err := ovs.BridgePortDelete(bridgeName, devName) + vswitch := ovs.NewOVS() + err := vswitch.BridgePortDelete(bridgeName, devName) if err != nil { return err } diff --git a/internal/server/network/network_utils_sriov.go b/internal/server/network/network_utils_sriov.go index 0cc7a9879e4..242e92cc9b9 100644 --- a/internal/server/network/network_utils_sriov.go +++ b/internal/server/network/network_utils_sriov.go @@ -375,10 +375,10 @@ func SRIOVFindFreeVFAndRepresentor(state *state.State, ovsBridgeName string) (st return "", "", "", -1, fmt.Errorf("Failed to read directory %q: %w", sysClassNet, err) } - ovs := ovs.NewOVS() + vswitch := ovs.NewOVS() // Get all ports on the integration bridge. - ports, err := ovs.BridgePortList(ovsBridgeName) + ports, err := vswitch.BridgePortList(ovsBridgeName) if err != nil { return "", "", "", -1, fmt.Errorf("Failed to get port list: %w", err) } From a8fda93de880a2f5615ee170c9da7f747c03e4c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Mon, 18 Dec 2023 23:39:56 -0500 Subject: [PATCH 22/38] tests: Skip lint on OVSDB schemas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- test/lint/newline-after-block.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lint/newline-after-block.sh b/test/lint/newline-after-block.sh index 21972bc50d6..8ce26e4ace4 100755 --- a/test/lint/newline-after-block.sh +++ b/test/lint/newline-after-block.sh @@ -3,7 +3,7 @@ echo "Checking that functional blocks are followed by newlines..." # Check all .go files except the protobuf bindings (.pb.go) -files=$(git ls-files --cached --modified --others '*.go' ':!:*.pb.go' ':!:test/mini-oidc/storage/*.go') +files=$(git ls-files --cached --modified --others '*.go' ':!:*.pb.go' ':!:test/mini-oidc/storage/*.go' ':!:internal/server/network/*/schema/*/*.go') exit_code=0 for file in $files From 3efcba5cbbb7d7148b524db197fcd16c60e06085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Tue, 19 Dec 2023 12:29:48 -0500 Subject: [PATCH 23/38] incusd/network/ovs: Re-organize the package MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber --- internal/server/network/ovs/ovs.go | 357 +----------------- internal/server/network/ovs/ovs_actions.go | 354 +++++++++++++++++ .../network/ovs/{shared.go => utils.go} | 0 3 files changed, 356 insertions(+), 355 deletions(-) create mode 100644 internal/server/network/ovs/ovs_actions.go rename internal/server/network/ovs/{shared.go => utils.go} (100%) diff --git a/internal/server/network/ovs/ovs.go b/internal/server/network/ovs/ovs.go index 64d688593e2..90b6303adfd 100644 --- a/internal/server/network/ovs/ovs.go +++ b/internal/server/network/ovs/ovs.go @@ -1,362 +1,9 @@ package ovs -import ( - "fmt" - "net" - "os/exec" - "strings" - "sync" - - "github.com/lxc/incus/internal/server/ip" - "github.com/lxc/incus/shared/subprocess" -) - -// ovnBridgeMappingMutex locks access to read/write external-ids:ovn-bridge-mappings. -var ovnBridgeMappingMutex sync.Mutex +// OVS command wrapper. +type OVS struct{} // NewOVS initialises new OVS wrapper. func NewOVS() *OVS { return &OVS{} } - -// OVS command wrapper. -type OVS struct{} - -// Installed returns true if OVS tools are installed. -func (o *OVS) Installed() bool { - _, err := exec.LookPath("ovs-vsctl") - return err == nil -} - -// BridgeExists returns true if OVS bridge exists. -func (o *OVS) BridgeExists(bridgeName string) (bool, error) { - _, err := subprocess.RunCommand("ovs-vsctl", "br-exists", bridgeName) - if err != nil { - runErr, ok := err.(subprocess.RunError) - if ok { - exitError, ok := runErr.Unwrap().(*exec.ExitError) - - // ovs-vsctl manpage says that br-exists exits with code 2 if bridge doesn't exist. - if ok && exitError.ExitCode() == 2 { - return false, nil - } - } - - return false, err - } - - return true, nil -} - -// BridgeAdd adds an OVS bridge. -func (o *OVS) BridgeAdd(bridgeName string, mayExist bool, hwaddr net.HardwareAddr, mtu uint32) error { - args := []string{} - - if mayExist { - args = append(args, "--may-exist") - } - - args = append(args, "add-br", bridgeName) - - if hwaddr != nil { - args = append(args, "--", "set", "bridge", bridgeName, fmt.Sprintf(`other-config:hwaddr="%s"`, hwaddr.String())) - } - - if mtu > 0 { - args = append(args, "--", "set", "int", bridgeName, fmt.Sprintf(`mtu_request=%d`, mtu)) - } - - _, err := subprocess.RunCommand("ovs-vsctl", args...) - if err != nil { - return err - } - - return nil -} - -// BridgeDelete deletes an OVS bridge. -func (o *OVS) BridgeDelete(bridgeName string) error { - _, err := subprocess.RunCommand("ovs-vsctl", "del-br", bridgeName) - if err != nil { - return err - } - - return nil -} - -// BridgePortAdd adds a port to the bridge (if already attached does nothing). -func (o *OVS) BridgePortAdd(bridgeName string, portName string, mayExist bool) error { - args := []string{} - - if mayExist { - args = append(args, "--may-exist") - } - - args = append(args, "add-port", bridgeName, portName) - - _, err := subprocess.RunCommand("ovs-vsctl", args...) - if err != nil { - return err - } - - return nil -} - -// BridgePortDelete deletes a port from the bridge (if already detached does nothing). -func (o *OVS) BridgePortDelete(bridgeName string, portName string) error { - _, err := subprocess.RunCommand("ovs-vsctl", "--if-exists", "del-port", bridgeName, portName) - if err != nil { - return err - } - - return nil -} - -// BridgePortSet sets port options. -func (o *OVS) BridgePortSet(portName string, options ...string) error { - _, err := subprocess.RunCommand("ovs-vsctl", append([]string{"set", "port", portName}, options...)...) - if err != nil { - return err - } - - return nil -} - -// InterfaceAssociateOVNSwitchPort removes any existing OVS ports associated to the specified ovnSwitchPortName -// and then associates the specified interfaceName to the OVN switch port. -func (o *OVS) InterfaceAssociateOVNSwitchPort(interfaceName string, ovnSwitchPortName string) error { - // Clear existing ports that were formerly associated to ovnSwitchPortName. - existingPorts, err := subprocess.RunCommand("ovs-vsctl", "--format=csv", "--no-headings", "--data=bare", "--colum=name", "find", "interface", fmt.Sprintf("external-ids:iface-id=%s", string(ovnSwitchPortName))) - if err != nil { - return err - } - - existingPorts = strings.TrimSpace(existingPorts) - if existingPorts != "" { - for _, port := range strings.Split(existingPorts, "\n") { - _, err = subprocess.RunCommand("ovs-vsctl", "del-port", port) - if err != nil { - return err - } - - // Atempt to remove port, but don't fail if doesn't exist or can't be removed, at least - // the OVS association has been successfully removed, so the new port being added next - // won't fail to work properly. - link := &ip.Link{Name: port} - _ = link.Delete() - } - } - - _, err = subprocess.RunCommand("ovs-vsctl", "set", "interface", interfaceName, fmt.Sprintf("external_ids:iface-id=%s", string(ovnSwitchPortName))) - if err != nil { - return err - } - - return nil -} - -// InterfaceAssociatedOVNSwitchPort returns the OVN switch port associated to the OVS interface. -func (o *OVS) InterfaceAssociatedOVNSwitchPort(interfaceName string) (string, error) { - ovnSwitchPort, err := subprocess.RunCommand("ovs-vsctl", "get", "interface", interfaceName, "external_ids:iface-id") - if err != nil { - return "", err - } - - return strings.TrimSpace(ovnSwitchPort), nil -} - -// ChassisID returns the local chassis ID. -func (o *OVS) ChassisID() (string, error) { - // ovs-vsctl's get command doesn't support its --format flag, so we always get the output quoted. - // However ovs-vsctl's find and list commands don't support retrieving a single column's map field. - // And ovs-vsctl's JSON output is unfriendly towards statically typed languages as it mixes data types - // in a slice. So stick with "get" command and use Go's strconv.Unquote to return the actual values. - chassisID, err := subprocess.RunCommand("ovs-vsctl", "get", "open_vswitch", ".", "external_ids:system-id") - if err != nil { - return "", err - } - - chassisID = strings.TrimSpace(chassisID) - chassisID, err = unquote(chassisID) - if err != nil { - return "", fmt.Errorf("Failed unquoting: %w", err) - } - - return chassisID, nil -} - -// OVNEncapIP returns the enscapsulation IP used for OVN underlay tunnels. -func (o *OVS) OVNEncapIP() (net.IP, error) { - // ovs-vsctl's get command doesn't support its --format flag, so we always get the output quoted. - // However ovs-vsctl's find and list commands don't support retrieving a single column's map field. - // And ovs-vsctl's JSON output is unfriendly towards statically typed languages as it mixes data types - // in a slice. So stick with "get" command and use Go's strconv.Unquote to return the actual values. - encapIPStr, err := subprocess.RunCommand("ovs-vsctl", "get", "open_vswitch", ".", "external_ids:ovn-encap-ip") - if err != nil { - return nil, err - } - - encapIPStr = strings.TrimSpace(encapIPStr) - encapIPStr, err = unquote(encapIPStr) - if err != nil { - return nil, fmt.Errorf("Failed unquoting: %w", err) - } - - encapIP := net.ParseIP(encapIPStr) - if encapIP == nil { - return nil, fmt.Errorf("Invalid ovn-encap-ip address") - } - - return encapIP, nil -} - -// OVNBridgeMappings gets the current OVN bridge mappings. -func (o *OVS) OVNBridgeMappings(bridgeName string) ([]string, error) { - // ovs-vsctl's get command doesn't support its --format flag, so we always get the output quoted. - // However ovs-vsctl's find and list commands don't support retrieving a single column's map field. - // And ovs-vsctl's JSON output is unfriendly towards statically typed languages as it mixes data types - // in a slice. So stick with "get" command and use Go's strconv.Unquote to return the actual values. - mappings, err := subprocess.RunCommand("ovs-vsctl", "--if-exists", "get", "open_vswitch", ".", "external-ids:ovn-bridge-mappings") - if err != nil { - return nil, err - } - - mappings = strings.TrimSpace(mappings) - if mappings == "" { - return []string{}, nil - } - - mappings, err = unquote(mappings) - if err != nil { - return nil, fmt.Errorf("Failed unquoting: %w", err) - } - - return strings.SplitN(mappings, ",", -1), nil -} - -// OVNBridgeMappingAdd appends an OVN bridge mapping between an OVS bridge and the logical provider name. -func (o *OVS) OVNBridgeMappingAdd(bridgeName string, providerName string) error { - ovnBridgeMappingMutex.Lock() - defer ovnBridgeMappingMutex.Unlock() - - mappings, err := o.OVNBridgeMappings(bridgeName) - if err != nil { - return err - } - - newMapping := fmt.Sprintf("%s:%s", providerName, bridgeName) - for _, mapping := range mappings { - if mapping == newMapping { - return nil // Mapping is already present, nothing to do. - } - } - - mappings = append(mappings, newMapping) - - // Set new mapping string back into OVS database. - _, err = subprocess.RunCommand("ovs-vsctl", "set", "open_vswitch", ".", fmt.Sprintf("external-ids:ovn-bridge-mappings=%s", strings.Join(mappings, ","))) - if err != nil { - return err - } - - return nil -} - -// OVNBridgeMappingDelete deletes an OVN bridge mapping between an OVS bridge and the logical provider name. -func (o *OVS) OVNBridgeMappingDelete(bridgeName string, providerName string) error { - ovnBridgeMappingMutex.Lock() - defer ovnBridgeMappingMutex.Unlock() - - mappings, err := o.OVNBridgeMappings(bridgeName) - if err != nil { - return err - } - - changed := false - newMappings := make([]string, 0, len(mappings)) - matchMapping := fmt.Sprintf("%s:%s", providerName, bridgeName) - for _, mapping := range mappings { - if mapping != matchMapping { - newMappings = append(newMappings, mapping) - } else { - changed = true - } - } - - if changed { - if len(newMappings) < 1 { - // Remove mapping key in OVS database. - _, err = subprocess.RunCommand("ovs-vsctl", "remove", "open_vswitch", ".", "external-ids", "ovn-bridge-mappings") - if err != nil { - return err - } - } else { - // Set updated mapping string back into OVS database. - _, err = subprocess.RunCommand("ovs-vsctl", "set", "open_vswitch", ".", fmt.Sprintf("external-ids:ovn-bridge-mappings=%s", strings.Join(newMappings, ","))) - if err != nil { - return err - } - } - } - - return nil -} - -// BridgePortList returns a list of ports that are connected to the bridge. -func (o *OVS) BridgePortList(bridgeName string) ([]string, error) { - // Clear existing ports that were formerly associated to ovnSwitchPortName. - portString, err := subprocess.RunCommand("ovs-vsctl", "list-ports", bridgeName) - if err != nil { - return nil, err - } - - ports := []string{} - - portString = strings.TrimSpace(portString) - if portString != "" { - for _, port := range strings.Split(portString, "\n") { - ports = append(ports, strings.TrimSpace(port)) - } - } - - return ports, nil -} - -// HardwareOffloadingEnabled returns true if hardware offloading is enabled. -func (o *OVS) HardwareOffloadingEnabled() bool { - // ovs-vsctl's get command doesn't support its --format flag, so we always get the output quoted. - // However ovs-vsctl's find and list commands don't support retrieving a single column's map field. - // And ovs-vsctl's JSON output is unfriendly towards statically typed languages as it mixes data types - // in a slice. So stick with "get" command and use Go's strconv.Unquote to return the actual values. - offload, err := subprocess.RunCommand("ovs-vsctl", "--if-exists", "get", "open_vswitch", ".", "other_config:hw-offload") - if err != nil { - return false - } - - offload = strings.TrimSpace(offload) - if offload == "" { - return false - } - - offload, err = unquote(offload) - if err != nil { - return false - } - - return offload == "true" -} - -// OVNSouthboundDBRemoteAddress gets the address of the southbound ovn database. -func (o *OVS) OVNSouthboundDBRemoteAddress() (string, error) { - result, err := subprocess.RunCommand("ovs-vsctl", "get", "open_vswitch", ".", "external_ids:ovn-remote") - if err != nil { - return "", err - } - - addr, err := unquote(strings.TrimSuffix(result, "\n")) - if err != nil { - return "", err - } - - return addr, nil -} diff --git a/internal/server/network/ovs/ovs_actions.go b/internal/server/network/ovs/ovs_actions.go new file mode 100644 index 00000000000..e0a7fc66ccf --- /dev/null +++ b/internal/server/network/ovs/ovs_actions.go @@ -0,0 +1,354 @@ +package ovs + +import ( + "fmt" + "net" + "os/exec" + "strings" + "sync" + + "github.com/lxc/incus/internal/server/ip" + "github.com/lxc/incus/shared/subprocess" +) + +// ovnBridgeMappingMutex locks access to read/write external-ids:ovn-bridge-mappings. +var ovnBridgeMappingMutex sync.Mutex + +// Installed returns true if OVS tools are installed. +func (o *OVS) Installed() bool { + _, err := exec.LookPath("ovs-vsctl") + return err == nil +} + +// BridgeExists returns true if OVS bridge exists. +func (o *OVS) BridgeExists(bridgeName string) (bool, error) { + _, err := subprocess.RunCommand("ovs-vsctl", "br-exists", bridgeName) + if err != nil { + runErr, ok := err.(subprocess.RunError) + if ok { + exitError, ok := runErr.Unwrap().(*exec.ExitError) + + // ovs-vsctl manpage says that br-exists exits with code 2 if bridge doesn't exist. + if ok && exitError.ExitCode() == 2 { + return false, nil + } + } + + return false, err + } + + return true, nil +} + +// BridgeAdd adds an OVS bridge. +func (o *OVS) BridgeAdd(bridgeName string, mayExist bool, hwaddr net.HardwareAddr, mtu uint32) error { + args := []string{} + + if mayExist { + args = append(args, "--may-exist") + } + + args = append(args, "add-br", bridgeName) + + if hwaddr != nil { + args = append(args, "--", "set", "bridge", bridgeName, fmt.Sprintf(`other-config:hwaddr="%s"`, hwaddr.String())) + } + + if mtu > 0 { + args = append(args, "--", "set", "int", bridgeName, fmt.Sprintf(`mtu_request=%d`, mtu)) + } + + _, err := subprocess.RunCommand("ovs-vsctl", args...) + if err != nil { + return err + } + + return nil +} + +// BridgeDelete deletes an OVS bridge. +func (o *OVS) BridgeDelete(bridgeName string) error { + _, err := subprocess.RunCommand("ovs-vsctl", "del-br", bridgeName) + if err != nil { + return err + } + + return nil +} + +// BridgePortAdd adds a port to the bridge (if already attached does nothing). +func (o *OVS) BridgePortAdd(bridgeName string, portName string, mayExist bool) error { + args := []string{} + + if mayExist { + args = append(args, "--may-exist") + } + + args = append(args, "add-port", bridgeName, portName) + + _, err := subprocess.RunCommand("ovs-vsctl", args...) + if err != nil { + return err + } + + return nil +} + +// BridgePortDelete deletes a port from the bridge (if already detached does nothing). +func (o *OVS) BridgePortDelete(bridgeName string, portName string) error { + _, err := subprocess.RunCommand("ovs-vsctl", "--if-exists", "del-port", bridgeName, portName) + if err != nil { + return err + } + + return nil +} + +// BridgePortSet sets port options. +func (o *OVS) BridgePortSet(portName string, options ...string) error { + _, err := subprocess.RunCommand("ovs-vsctl", append([]string{"set", "port", portName}, options...)...) + if err != nil { + return err + } + + return nil +} + +// InterfaceAssociateOVNSwitchPort removes any existing OVS ports associated to the specified ovnSwitchPortName +// and then associates the specified interfaceName to the OVN switch port. +func (o *OVS) InterfaceAssociateOVNSwitchPort(interfaceName string, ovnSwitchPortName string) error { + // Clear existing ports that were formerly associated to ovnSwitchPortName. + existingPorts, err := subprocess.RunCommand("ovs-vsctl", "--format=csv", "--no-headings", "--data=bare", "--colum=name", "find", "interface", fmt.Sprintf("external-ids:iface-id=%s", string(ovnSwitchPortName))) + if err != nil { + return err + } + + existingPorts = strings.TrimSpace(existingPorts) + if existingPorts != "" { + for _, port := range strings.Split(existingPorts, "\n") { + _, err = subprocess.RunCommand("ovs-vsctl", "del-port", port) + if err != nil { + return err + } + + // Atempt to remove port, but don't fail if doesn't exist or can't be removed, at least + // the OVS association has been successfully removed, so the new port being added next + // won't fail to work properly. + link := &ip.Link{Name: port} + _ = link.Delete() + } + } + + _, err = subprocess.RunCommand("ovs-vsctl", "set", "interface", interfaceName, fmt.Sprintf("external_ids:iface-id=%s", string(ovnSwitchPortName))) + if err != nil { + return err + } + + return nil +} + +// InterfaceAssociatedOVNSwitchPort returns the OVN switch port associated to the OVS interface. +func (o *OVS) InterfaceAssociatedOVNSwitchPort(interfaceName string) (string, error) { + ovnSwitchPort, err := subprocess.RunCommand("ovs-vsctl", "get", "interface", interfaceName, "external_ids:iface-id") + if err != nil { + return "", err + } + + return strings.TrimSpace(ovnSwitchPort), nil +} + +// ChassisID returns the local chassis ID. +func (o *OVS) ChassisID() (string, error) { + // ovs-vsctl's get command doesn't support its --format flag, so we always get the output quoted. + // However ovs-vsctl's find and list commands don't support retrieving a single column's map field. + // And ovs-vsctl's JSON output is unfriendly towards statically typed languages as it mixes data types + // in a slice. So stick with "get" command and use Go's strconv.Unquote to return the actual values. + chassisID, err := subprocess.RunCommand("ovs-vsctl", "get", "open_vswitch", ".", "external_ids:system-id") + if err != nil { + return "", err + } + + chassisID = strings.TrimSpace(chassisID) + chassisID, err = unquote(chassisID) + if err != nil { + return "", fmt.Errorf("Failed unquoting: %w", err) + } + + return chassisID, nil +} + +// OVNEncapIP returns the enscapsulation IP used for OVN underlay tunnels. +func (o *OVS) OVNEncapIP() (net.IP, error) { + // ovs-vsctl's get command doesn't support its --format flag, so we always get the output quoted. + // However ovs-vsctl's find and list commands don't support retrieving a single column's map field. + // And ovs-vsctl's JSON output is unfriendly towards statically typed languages as it mixes data types + // in a slice. So stick with "get" command and use Go's strconv.Unquote to return the actual values. + encapIPStr, err := subprocess.RunCommand("ovs-vsctl", "get", "open_vswitch", ".", "external_ids:ovn-encap-ip") + if err != nil { + return nil, err + } + + encapIPStr = strings.TrimSpace(encapIPStr) + encapIPStr, err = unquote(encapIPStr) + if err != nil { + return nil, fmt.Errorf("Failed unquoting: %w", err) + } + + encapIP := net.ParseIP(encapIPStr) + if encapIP == nil { + return nil, fmt.Errorf("Invalid ovn-encap-ip address") + } + + return encapIP, nil +} + +// OVNBridgeMappings gets the current OVN bridge mappings. +func (o *OVS) OVNBridgeMappings(bridgeName string) ([]string, error) { + // ovs-vsctl's get command doesn't support its --format flag, so we always get the output quoted. + // However ovs-vsctl's find and list commands don't support retrieving a single column's map field. + // And ovs-vsctl's JSON output is unfriendly towards statically typed languages as it mixes data types + // in a slice. So stick with "get" command and use Go's strconv.Unquote to return the actual values. + mappings, err := subprocess.RunCommand("ovs-vsctl", "--if-exists", "get", "open_vswitch", ".", "external-ids:ovn-bridge-mappings") + if err != nil { + return nil, err + } + + mappings = strings.TrimSpace(mappings) + if mappings == "" { + return []string{}, nil + } + + mappings, err = unquote(mappings) + if err != nil { + return nil, fmt.Errorf("Failed unquoting: %w", err) + } + + return strings.SplitN(mappings, ",", -1), nil +} + +// OVNBridgeMappingAdd appends an OVN bridge mapping between an OVS bridge and the logical provider name. +func (o *OVS) OVNBridgeMappingAdd(bridgeName string, providerName string) error { + ovnBridgeMappingMutex.Lock() + defer ovnBridgeMappingMutex.Unlock() + + mappings, err := o.OVNBridgeMappings(bridgeName) + if err != nil { + return err + } + + newMapping := fmt.Sprintf("%s:%s", providerName, bridgeName) + for _, mapping := range mappings { + if mapping == newMapping { + return nil // Mapping is already present, nothing to do. + } + } + + mappings = append(mappings, newMapping) + + // Set new mapping string back into OVS database. + _, err = subprocess.RunCommand("ovs-vsctl", "set", "open_vswitch", ".", fmt.Sprintf("external-ids:ovn-bridge-mappings=%s", strings.Join(mappings, ","))) + if err != nil { + return err + } + + return nil +} + +// OVNBridgeMappingDelete deletes an OVN bridge mapping between an OVS bridge and the logical provider name. +func (o *OVS) OVNBridgeMappingDelete(bridgeName string, providerName string) error { + ovnBridgeMappingMutex.Lock() + defer ovnBridgeMappingMutex.Unlock() + + mappings, err := o.OVNBridgeMappings(bridgeName) + if err != nil { + return err + } + + changed := false + newMappings := make([]string, 0, len(mappings)) + matchMapping := fmt.Sprintf("%s:%s", providerName, bridgeName) + for _, mapping := range mappings { + if mapping != matchMapping { + newMappings = append(newMappings, mapping) + } else { + changed = true + } + } + + if changed { + if len(newMappings) < 1 { + // Remove mapping key in OVS database. + _, err = subprocess.RunCommand("ovs-vsctl", "remove", "open_vswitch", ".", "external-ids", "ovn-bridge-mappings") + if err != nil { + return err + } + } else { + // Set updated mapping string back into OVS database. + _, err = subprocess.RunCommand("ovs-vsctl", "set", "open_vswitch", ".", fmt.Sprintf("external-ids:ovn-bridge-mappings=%s", strings.Join(newMappings, ","))) + if err != nil { + return err + } + } + } + + return nil +} + +// BridgePortList returns a list of ports that are connected to the bridge. +func (o *OVS) BridgePortList(bridgeName string) ([]string, error) { + // Clear existing ports that were formerly associated to ovnSwitchPortName. + portString, err := subprocess.RunCommand("ovs-vsctl", "list-ports", bridgeName) + if err != nil { + return nil, err + } + + ports := []string{} + + portString = strings.TrimSpace(portString) + if portString != "" { + for _, port := range strings.Split(portString, "\n") { + ports = append(ports, strings.TrimSpace(port)) + } + } + + return ports, nil +} + +// HardwareOffloadingEnabled returns true if hardware offloading is enabled. +func (o *OVS) HardwareOffloadingEnabled() bool { + // ovs-vsctl's get command doesn't support its --format flag, so we always get the output quoted. + // However ovs-vsctl's find and list commands don't support retrieving a single column's map field. + // And ovs-vsctl's JSON output is unfriendly towards statically typed languages as it mixes data types + // in a slice. So stick with "get" command and use Go's strconv.Unquote to return the actual values. + offload, err := subprocess.RunCommand("ovs-vsctl", "--if-exists", "get", "open_vswitch", ".", "other_config:hw-offload") + if err != nil { + return false + } + + offload = strings.TrimSpace(offload) + if offload == "" { + return false + } + + offload, err = unquote(offload) + if err != nil { + return false + } + + return offload == "true" +} + +// OVNSouthboundDBRemoteAddress gets the address of the southbound ovn database. +func (o *OVS) OVNSouthboundDBRemoteAddress() (string, error) { + result, err := subprocess.RunCommand("ovs-vsctl", "get", "open_vswitch", ".", "external_ids:ovn-remote") + if err != nil { + return "", err + } + + addr, err := unquote(strings.TrimSuffix(result, "\n")) + if err != nil { + return "", err + } + + return addr, nil +} diff --git a/internal/server/network/ovs/shared.go b/internal/server/network/ovs/utils.go similarity index 100% rename from internal/server/network/ovs/shared.go rename to internal/server/network/ovs/utils.go From dd2f1f4b845b18c8757c10ad39e2d40cd5b372eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Tue, 19 Dec 2023 12:33:25 -0500 Subject: [PATCH 24/38] incusd/network/ovs: Rename OVS struct to VSwitch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- internal/server/network/ovs/ovs.go | 10 ++-- internal/server/network/ovs/ovs_actions.go | 58 +++++++++++----------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/internal/server/network/ovs/ovs.go b/internal/server/network/ovs/ovs.go index 90b6303adfd..c11c4bdc1e8 100644 --- a/internal/server/network/ovs/ovs.go +++ b/internal/server/network/ovs/ovs.go @@ -1,9 +1,9 @@ package ovs -// OVS command wrapper. -type OVS struct{} +// VSwitch client. +type VSwitch struct{} -// NewOVS initialises new OVS wrapper. -func NewOVS() *OVS { - return &OVS{} +// NewVSwitch initialises a new vSwitch client.. +func NewVSwitch() *VSwitch { + return &VSwitch{} } diff --git a/internal/server/network/ovs/ovs_actions.go b/internal/server/network/ovs/ovs_actions.go index e0a7fc66ccf..521382a8f8d 100644 --- a/internal/server/network/ovs/ovs_actions.go +++ b/internal/server/network/ovs/ovs_actions.go @@ -14,14 +14,14 @@ import ( // ovnBridgeMappingMutex locks access to read/write external-ids:ovn-bridge-mappings. var ovnBridgeMappingMutex sync.Mutex -// Installed returns true if OVS tools are installed. -func (o *OVS) Installed() bool { +// Installed returns true if the OVS tools are installed. +func (o *VSwitch) Installed() bool { _, err := exec.LookPath("ovs-vsctl") return err == nil } -// BridgeExists returns true if OVS bridge exists. -func (o *OVS) BridgeExists(bridgeName string) (bool, error) { +// BridgeExists returns true if the bridge exists. +func (o *VSwitch) BridgeExists(bridgeName string) (bool, error) { _, err := subprocess.RunCommand("ovs-vsctl", "br-exists", bridgeName) if err != nil { runErr, ok := err.(subprocess.RunError) @@ -40,8 +40,8 @@ func (o *OVS) BridgeExists(bridgeName string) (bool, error) { return true, nil } -// BridgeAdd adds an OVS bridge. -func (o *OVS) BridgeAdd(bridgeName string, mayExist bool, hwaddr net.HardwareAddr, mtu uint32) error { +// BridgeAdd adds a new bridge. +func (o *VSwitch) BridgeAdd(bridgeName string, mayExist bool, hwaddr net.HardwareAddr, mtu uint32) error { args := []string{} if mayExist { @@ -66,8 +66,8 @@ func (o *OVS) BridgeAdd(bridgeName string, mayExist bool, hwaddr net.HardwareAdd return nil } -// BridgeDelete deletes an OVS bridge. -func (o *OVS) BridgeDelete(bridgeName string) error { +// BridgeDelete deletes a bridge. +func (o *VSwitch) BridgeDelete(bridgeName string) error { _, err := subprocess.RunCommand("ovs-vsctl", "del-br", bridgeName) if err != nil { return err @@ -77,7 +77,7 @@ func (o *OVS) BridgeDelete(bridgeName string) error { } // BridgePortAdd adds a port to the bridge (if already attached does nothing). -func (o *OVS) BridgePortAdd(bridgeName string, portName string, mayExist bool) error { +func (o *VSwitch) BridgePortAdd(bridgeName string, portName string, mayExist bool) error { args := []string{} if mayExist { @@ -95,7 +95,7 @@ func (o *OVS) BridgePortAdd(bridgeName string, portName string, mayExist bool) e } // BridgePortDelete deletes a port from the bridge (if already detached does nothing). -func (o *OVS) BridgePortDelete(bridgeName string, portName string) error { +func (o *VSwitch) BridgePortDelete(bridgeName string, portName string) error { _, err := subprocess.RunCommand("ovs-vsctl", "--if-exists", "del-port", bridgeName, portName) if err != nil { return err @@ -105,7 +105,7 @@ func (o *OVS) BridgePortDelete(bridgeName string, portName string) error { } // BridgePortSet sets port options. -func (o *OVS) BridgePortSet(portName string, options ...string) error { +func (o *VSwitch) BridgePortSet(portName string, options ...string) error { _, err := subprocess.RunCommand("ovs-vsctl", append([]string{"set", "port", portName}, options...)...) if err != nil { return err @@ -114,9 +114,9 @@ func (o *OVS) BridgePortSet(portName string, options ...string) error { return nil } -// InterfaceAssociateOVNSwitchPort removes any existing OVS ports associated to the specified ovnSwitchPortName +// InterfaceAssociateOVNSwitchPort removes any existing switch ports associated to the specified ovnSwitchPortName // and then associates the specified interfaceName to the OVN switch port. -func (o *OVS) InterfaceAssociateOVNSwitchPort(interfaceName string, ovnSwitchPortName string) error { +func (o *VSwitch) InterfaceAssociateOVNSwitchPort(interfaceName string, ovnSwitchPortName string) error { // Clear existing ports that were formerly associated to ovnSwitchPortName. existingPorts, err := subprocess.RunCommand("ovs-vsctl", "--format=csv", "--no-headings", "--data=bare", "--colum=name", "find", "interface", fmt.Sprintf("external-ids:iface-id=%s", string(ovnSwitchPortName))) if err != nil { @@ -132,7 +132,7 @@ func (o *OVS) InterfaceAssociateOVNSwitchPort(interfaceName string, ovnSwitchPor } // Atempt to remove port, but don't fail if doesn't exist or can't be removed, at least - // the OVS association has been successfully removed, so the new port being added next + // the switch association has been successfully removed, so the new port being added next // won't fail to work properly. link := &ip.Link{Name: port} _ = link.Delete() @@ -147,8 +147,8 @@ func (o *OVS) InterfaceAssociateOVNSwitchPort(interfaceName string, ovnSwitchPor return nil } -// InterfaceAssociatedOVNSwitchPort returns the OVN switch port associated to the OVS interface. -func (o *OVS) InterfaceAssociatedOVNSwitchPort(interfaceName string) (string, error) { +// InterfaceAssociatedOVNSwitchPort returns the OVN switch port associated to the interface. +func (o *VSwitch) InterfaceAssociatedOVNSwitchPort(interfaceName string) (string, error) { ovnSwitchPort, err := subprocess.RunCommand("ovs-vsctl", "get", "interface", interfaceName, "external_ids:iface-id") if err != nil { return "", err @@ -158,7 +158,7 @@ func (o *OVS) InterfaceAssociatedOVNSwitchPort(interfaceName string) (string, er } // ChassisID returns the local chassis ID. -func (o *OVS) ChassisID() (string, error) { +func (o *VSwitch) ChassisID() (string, error) { // ovs-vsctl's get command doesn't support its --format flag, so we always get the output quoted. // However ovs-vsctl's find and list commands don't support retrieving a single column's map field. // And ovs-vsctl's JSON output is unfriendly towards statically typed languages as it mixes data types @@ -178,7 +178,7 @@ func (o *OVS) ChassisID() (string, error) { } // OVNEncapIP returns the enscapsulation IP used for OVN underlay tunnels. -func (o *OVS) OVNEncapIP() (net.IP, error) { +func (o *VSwitch) OVNEncapIP() (net.IP, error) { // ovs-vsctl's get command doesn't support its --format flag, so we always get the output quoted. // However ovs-vsctl's find and list commands don't support retrieving a single column's map field. // And ovs-vsctl's JSON output is unfriendly towards statically typed languages as it mixes data types @@ -203,7 +203,7 @@ func (o *OVS) OVNEncapIP() (net.IP, error) { } // OVNBridgeMappings gets the current OVN bridge mappings. -func (o *OVS) OVNBridgeMappings(bridgeName string) ([]string, error) { +func (o *VSwitch) OVNBridgeMappings(bridgeName string) ([]string, error) { // ovs-vsctl's get command doesn't support its --format flag, so we always get the output quoted. // However ovs-vsctl's find and list commands don't support retrieving a single column's map field. // And ovs-vsctl's JSON output is unfriendly towards statically typed languages as it mixes data types @@ -226,8 +226,8 @@ func (o *OVS) OVNBridgeMappings(bridgeName string) ([]string, error) { return strings.SplitN(mappings, ",", -1), nil } -// OVNBridgeMappingAdd appends an OVN bridge mapping between an OVS bridge and the logical provider name. -func (o *OVS) OVNBridgeMappingAdd(bridgeName string, providerName string) error { +// OVNBridgeMappingAdd appends an OVN bridge mapping between a bridge and the logical provider name. +func (o *VSwitch) OVNBridgeMappingAdd(bridgeName string, providerName string) error { ovnBridgeMappingMutex.Lock() defer ovnBridgeMappingMutex.Unlock() @@ -245,7 +245,7 @@ func (o *OVS) OVNBridgeMappingAdd(bridgeName string, providerName string) error mappings = append(mappings, newMapping) - // Set new mapping string back into OVS database. + // Set new mapping string back into the database. _, err = subprocess.RunCommand("ovs-vsctl", "set", "open_vswitch", ".", fmt.Sprintf("external-ids:ovn-bridge-mappings=%s", strings.Join(mappings, ","))) if err != nil { return err @@ -254,8 +254,8 @@ func (o *OVS) OVNBridgeMappingAdd(bridgeName string, providerName string) error return nil } -// OVNBridgeMappingDelete deletes an OVN bridge mapping between an OVS bridge and the logical provider name. -func (o *OVS) OVNBridgeMappingDelete(bridgeName string, providerName string) error { +// OVNBridgeMappingDelete deletes an OVN bridge mapping between a bridge and the logical provider name. +func (o *VSwitch) OVNBridgeMappingDelete(bridgeName string, providerName string) error { ovnBridgeMappingMutex.Lock() defer ovnBridgeMappingMutex.Unlock() @@ -277,13 +277,13 @@ func (o *OVS) OVNBridgeMappingDelete(bridgeName string, providerName string) err if changed { if len(newMappings) < 1 { - // Remove mapping key in OVS database. + // Remove mapping key in the database. _, err = subprocess.RunCommand("ovs-vsctl", "remove", "open_vswitch", ".", "external-ids", "ovn-bridge-mappings") if err != nil { return err } } else { - // Set updated mapping string back into OVS database. + // Set updated mapping string back into the database. _, err = subprocess.RunCommand("ovs-vsctl", "set", "open_vswitch", ".", fmt.Sprintf("external-ids:ovn-bridge-mappings=%s", strings.Join(newMappings, ","))) if err != nil { return err @@ -295,7 +295,7 @@ func (o *OVS) OVNBridgeMappingDelete(bridgeName string, providerName string) err } // BridgePortList returns a list of ports that are connected to the bridge. -func (o *OVS) BridgePortList(bridgeName string) ([]string, error) { +func (o *VSwitch) BridgePortList(bridgeName string) ([]string, error) { // Clear existing ports that were formerly associated to ovnSwitchPortName. portString, err := subprocess.RunCommand("ovs-vsctl", "list-ports", bridgeName) if err != nil { @@ -315,7 +315,7 @@ func (o *OVS) BridgePortList(bridgeName string) ([]string, error) { } // HardwareOffloadingEnabled returns true if hardware offloading is enabled. -func (o *OVS) HardwareOffloadingEnabled() bool { +func (o *VSwitch) HardwareOffloadingEnabled() bool { // ovs-vsctl's get command doesn't support its --format flag, so we always get the output quoted. // However ovs-vsctl's find and list commands don't support retrieving a single column's map field. // And ovs-vsctl's JSON output is unfriendly towards statically typed languages as it mixes data types @@ -339,7 +339,7 @@ func (o *OVS) HardwareOffloadingEnabled() bool { } // OVNSouthboundDBRemoteAddress gets the address of the southbound ovn database. -func (o *OVS) OVNSouthboundDBRemoteAddress() (string, error) { +func (o *VSwitch) OVNSouthboundDBRemoteAddress() (string, error) { result, err := subprocess.RunCommand("ovs-vsctl", "get", "open_vswitch", ".", "external_ids:ovn-remote") if err != nil { return "", err From 4f03fc150b1582dfb894bb98f171983eaa12fa13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Tue, 19 Dec 2023 12:35:41 -0500 Subject: [PATCH 25/38] incusd: Update for NewVSwitch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- cmd/incusd/networks.go | 2 +- internal/server/device/nic_bridged.go | 2 +- internal/server/device/nic_ovn.go | 10 +++++----- internal/server/network/driver_bridge.go | 4 ++-- internal/server/network/driver_ovn.go | 18 +++++++++--------- .../server/network/network_utils_bridge.go | 4 ++-- internal/server/network/network_utils_sriov.go | 2 +- internal/server/network/ovn/ovn.go | 2 +- 8 files changed, 22 insertions(+), 22 deletions(-) diff --git a/cmd/incusd/networks.go b/cmd/incusd/networks.go index 49d5ede65e1..cab51dfde35 100644 --- a/cmd/incusd/networks.go +++ b/cmd/incusd/networks.go @@ -865,7 +865,7 @@ func doNetworkGet(s *state.State, r *http.Request, allNodes bool, projectName st } else if util.PathExists(fmt.Sprintf("/sys/class/net/%s/bonding", apiNet.Name)) { apiNet.Type = "bond" } else { - vswitch := ovs.NewOVS() + vswitch := ovs.NewVSwitch() exists, _ := vswitch.BridgeExists(apiNet.Name) if exists { apiNet.Type = "bridge" diff --git a/internal/server/device/nic_bridged.go b/internal/server/device/nic_bridged.go index 6c1b3ade18d..fae0e3f1dbd 100644 --- a/internal/server/device/nic_bridged.go +++ b/internal/server/device/nic_bridged.go @@ -1529,7 +1529,7 @@ func (d *nicBridged) setupNativeBridgePortVLANs(hostName string) error { // setupOVSBridgePortVLANs configures the bridge port with the specified VLAN settings on the openvswitch bridge. func (d *nicBridged) setupOVSBridgePortVLANs(hostName string) error { - vswitch := ovs.NewOVS() + vswitch := ovs.NewVSwitch() // Set port on bridge to specified untagged PVID. if d.config["vlan"] != "" { diff --git a/internal/server/device/nic_ovn.go b/internal/server/device/nic_ovn.go index 5d72a6e8d63..75a31d8b294 100644 --- a/internal/server/device/nic_ovn.go +++ b/internal/server/device/nic_ovn.go @@ -409,7 +409,7 @@ func (d *nicOVN) Start() (*deviceConfig.RunConfig, error) { delete(saveData, "host_name") // Nested NICs don't have a host side interface. } else { if d.config["acceleration"] == "sriov" { - vswitch := ovs.NewOVS() + vswitch := ovs.NewVSwitch() if !vswitch.HardwareOffloadingEnabled() { return nil, fmt.Errorf("SR-IOV acceleration requires hardware offloading be enabled in OVS") } @@ -456,7 +456,7 @@ func (d *nicOVN) Start() (*deviceConfig.RunConfig, error) { integrationBridgeNICName = vfRepresentor peerName = vfDev } else if d.config["acceleration"] == "vdpa" { - vswitch := ovs.NewOVS() + vswitch := ovs.NewVSwitch() if !vswitch.HardwareOffloadingEnabled() { return nil, fmt.Errorf("SR-IOV acceleration requires hardware offloading be enabled in OVS") } @@ -609,7 +609,7 @@ func (d *nicOVN) Start() (*deviceConfig.RunConfig, error) { runConf := deviceConfig.RunConfig{} // Get local chassis ID for chassis group. - vswitch := ovs.NewOVS() + vswitch := ovs.NewVSwitch() chassisID, err := vswitch.ChassisID() if err != nil { return nil, fmt.Errorf("Failed getting OVS Chassis ID: %w", err) @@ -825,7 +825,7 @@ func (d *nicOVN) Stop() (*deviceConfig.RunConfig, error) { // port name using the same regime it does for new ports. This part is only here in order to allow // instance ports generated under an older regime to be cleaned up properly. networkVethFillFromVolatile(d.config, v) - vswitch := ovs.NewOVS() + vswitch := ovs.NewVSwitch() var ovsExternalOVNPort string if d.config["nested"] == "" { ovsExternalOVNPort, err = vswitch.InterfaceAssociatedOVNSwitchPort(d.config["host_name"]) @@ -1127,7 +1127,7 @@ func (d *nicOVN) setupHostNIC(hostName string, ovnPortName ovn.OVNSwitchPort, up // Attach host side veth interface to bridge. integrationBridge := d.state.GlobalConfig.NetworkOVNIntegrationBridge() - vswitch := ovs.NewOVS() + vswitch := ovs.NewVSwitch() err = vswitch.BridgePortAdd(integrationBridge, hostName, true) if err != nil { return nil, err diff --git a/internal/server/network/driver_bridge.go b/internal/server/network/driver_bridge.go index 5325184116f..48ad854c43e 100644 --- a/internal/server/network/driver_bridge.go +++ b/internal/server/network/driver_bridge.go @@ -581,7 +581,7 @@ func (n *bridge) setup(oldConfig map[string]string) error { // Create the bridge interface if doesn't exist. if !n.isRunning() { if n.config["bridge.driver"] == "openvswitch" { - vswitch := ovs.NewOVS() + vswitch := ovs.NewVSwitch() if !vswitch.Installed() { return fmt.Errorf("Open vSwitch isn't installed on this system") } @@ -1440,7 +1440,7 @@ func (n *bridge) Stop() error { // Destroy the bridge interface if n.config["bridge.driver"] == "openvswitch" { - vswitch := ovs.NewOVS() + vswitch := ovs.NewVSwitch() err := vswitch.BridgeDelete(n.name) if err != nil { return err diff --git a/internal/server/network/driver_ovn.go b/internal/server/network/driver_ovn.go index 9e2ff4848eb..ef1442b7bc1 100644 --- a/internal/server/network/driver_ovn.go +++ b/internal/server/network/driver_ovn.go @@ -654,7 +654,7 @@ func (n *ovn) getUnderlayInfo() (uint32, net.IP, error) { return 0, fmt.Errorf("No matching interface found for OVN enscapsulation IP %q", findIP.String()) } - vswitch := ovs.NewOVS() + vswitch := ovs.NewVSwitch() encapIP, err := vswitch.OVNEncapIP() if err != nil { return 0, nil, fmt.Errorf("Failed getting OVN enscapsulation IP from OVS: %w", err) @@ -1278,7 +1278,7 @@ func (n *ovn) startUplinkPortBridgeNative(uplinkNet Network, bridgeDevice string } // Create uplink OVS bridge if needed. - vswitch := ovs.NewOVS() + vswitch := ovs.NewVSwitch() err = vswitch.BridgeAdd(vars.ovsBridge, true, nil, 0) if err != nil { return fmt.Errorf("Failed to create uplink OVS bridge %q: %w", vars.ovsBridge, err) @@ -1310,7 +1310,7 @@ func (n *ovn) startUplinkPortBridgeOVS(uplinkNet Network, bridgeDevice string) e defer revert.Fail() // If uplink is an openvswitch bridge, have OVN logical provider connect directly to it. - vswitch := ovs.NewOVS() + vswitch := ovs.NewVSwitch() err := vswitch.OVNBridgeMappingAdd(bridgeDevice, uplinkNet.Name()) if err != nil { return fmt.Errorf("Failed to associate uplink OVS bridge %q to OVN provider %q: %w", bridgeDevice, uplinkNet.Name(), err) @@ -1386,7 +1386,7 @@ func (n *ovn) startUplinkPortPhysical(uplinkNet Network) error { } // Detect if uplink interface is a OVS bridge. - vswitch := ovs.NewOVS() + vswitch := ovs.NewVSwitch() isOVSBridge, _ := vswitch.BridgeExists(uplinkHostName) if isOVSBridge { return n.startUplinkPortBridgeOVS(uplinkNet, uplinkHostName) @@ -1530,7 +1530,7 @@ func (n *ovn) deleteUplinkPortBridgeNative(uplinkNet Network) error { if !uplinkUsed { removeVeths = true - vswitch := ovs.NewOVS() + vswitch := ovs.NewVSwitch() err = vswitch.OVNBridgeMappingDelete(vars.ovsBridge, uplinkNet.Name()) if err != nil { return err @@ -1576,7 +1576,7 @@ func (n *ovn) deleteUplinkPortBridgeOVS(uplinkNet Network, ovsBridge string) err // Remove uplink OVS bridge mapping if not in use by other OVN networks. if !uplinkUsed { - vswitch := ovs.NewOVS() + vswitch := ovs.NewVSwitch() err = vswitch.OVNBridgeMappingDelete(ovsBridge, uplinkNet.Name()) if err != nil { return err @@ -1597,7 +1597,7 @@ func (n *ovn) deleteUplinkPortPhysical(uplinkNet Network) error { } // Detect if uplink interface is a OVS bridge. - vswitch := ovs.NewOVS() + vswitch := ovs.NewVSwitch() isOVSBridge, _ := vswitch.BridgeExists(uplinkHostName) if isOVSBridge { return n.deleteUplinkPortBridgeOVS(uplinkNet, uplinkHostName) @@ -2515,7 +2515,7 @@ func (n *ovn) addChassisGroupEntry() error { } // Get local chassis ID for chassis group. - vswitch := ovs.NewOVS() + vswitch := ovs.NewVSwitch() chassisID, err := vswitch.ChassisID() if err != nil { return fmt.Errorf("Failed getting OVS Chassis ID: %w", err) @@ -2580,7 +2580,7 @@ func (n *ovn) deleteChassisGroupEntry() error { } // Remove local chassis from chassis group. - vswitch := ovs.NewOVS() + vswitch := ovs.NewVSwitch() chassisID, err := vswitch.ChassisID() if err != nil { return fmt.Errorf("Failed getting OVS Chassis ID: %w", err) diff --git a/internal/server/network/network_utils_bridge.go b/internal/server/network/network_utils_bridge.go index cb69d8a6648..fccdfc77531 100644 --- a/internal/server/network/network_utils_bridge.go +++ b/internal/server/network/network_utils_bridge.go @@ -64,7 +64,7 @@ func AttachInterface(bridgeName string, devName string) error { return err } } else { - vswitch := ovs.NewOVS() + vswitch := ovs.NewVSwitch() err := vswitch.BridgePortAdd(bridgeName, devName, true) if err != nil { return err @@ -83,7 +83,7 @@ func DetachInterface(bridgeName string, devName string) error { return err } } else { - vswitch := ovs.NewOVS() + vswitch := ovs.NewVSwitch() err := vswitch.BridgePortDelete(bridgeName, devName) if err != nil { return err diff --git a/internal/server/network/network_utils_sriov.go b/internal/server/network/network_utils_sriov.go index 242e92cc9b9..f482ca8b519 100644 --- a/internal/server/network/network_utils_sriov.go +++ b/internal/server/network/network_utils_sriov.go @@ -375,7 +375,7 @@ func SRIOVFindFreeVFAndRepresentor(state *state.State, ovsBridgeName string) (st return "", "", "", -1, fmt.Errorf("Failed to read directory %q: %w", sysClassNet, err) } - vswitch := ovs.NewOVS() + vswitch := ovs.NewVSwitch() // Get all ports on the integration bridge. ports, err := vswitch.BridgePortList(ovsBridgeName) diff --git a/internal/server/network/ovn/ovn.go b/internal/server/network/ovn/ovn.go index 0eeb8c4dabb..7d9f0a69804 100644 --- a/internal/server/network/ovn/ovn.go +++ b/internal/server/network/ovn/ovn.go @@ -26,7 +26,7 @@ import ( func NewOVN(s *state.State) (*OVN, error) { // Get database connection strings. nbConnection := s.GlobalConfig.NetworkOVNNorthboundConnection() - sbConnection, err := ovs.NewOVS().OVNSouthboundDBRemoteAddress() + sbConnection, err := ovs.NewVSwitch().OVNSouthboundDBRemoteAddress() if err != nil { return nil, fmt.Errorf("Failed to get OVN southbound connection string: %w", err) } From d4c618633dd81af82b526cef217e8c9ad9b21a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Tue, 19 Dec 2023 12:42:25 -0500 Subject: [PATCH 26/38] incusd/network/ovn: Re-organize the package MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- internal/server/network/ovn/{shared.go => utils.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename internal/server/network/ovn/{shared.go => utils.go} (100%) diff --git a/internal/server/network/ovn/shared.go b/internal/server/network/ovn/utils.go similarity index 100% rename from internal/server/network/ovn/shared.go rename to internal/server/network/ovn/utils.go From c2aa6f2839506720acc8dc5e0d13f602c7f15766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Tue, 19 Dec 2023 13:57:45 -0500 Subject: [PATCH 27/38] incusd/network/ovn: Add new Southbound client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- internal/server/network/ovn/ovn_sb.go | 198 ++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 internal/server/network/ovn/ovn_sb.go diff --git a/internal/server/network/ovn/ovn_sb.go b/internal/server/network/ovn/ovn_sb.go new file mode 100644 index 00000000000..8bebda86507 --- /dev/null +++ b/internal/server/network/ovn/ovn_sb.go @@ -0,0 +1,198 @@ +package ovn + +import ( + "context" + "crypto/tls" + "crypto/x509" + "encoding/pem" + "fmt" + "os" + "runtime" + "strings" + + "github.com/go-logr/logr" + ovsdbClient "github.com/ovn-org/libovsdb/client" + + ovnSB "github.com/lxc/incus/internal/server/network/ovn/schema/ovn-sb" + "github.com/lxc/incus/internal/server/network/ovs" + "github.com/lxc/incus/internal/server/state" +) + +// SB client. +type SB struct { + client ovsdbClient.Client + cookie ovsdbClient.MonitorCookie +} + +// NewSB initialises new OVN client for Southbound operations. +func NewSB(s *state.State) (*SB, error) { + // Get the database connection string. + dbAddr, err := ovs.NewVSwitch().OVNSouthboundDBRemoteAddress() + if err != nil { + return nil, fmt.Errorf("Failed to get OVN southbound connection string: %w", err) + } + + // Prepare the OVSDB client. + dbSchema, err := ovnSB.FullDatabaseModel() + if err != nil { + return nil, err + } + + discard := logr.Discard() + + options := []ovsdbClient.Option{ovsdbClient.WithLogger(&discard)} + for _, entry := range strings.Split(dbAddr, ",") { + options = append(options, ovsdbClient.WithEndpoint(entry)) + } + + // Handle SSL. + if strings.Contains(dbAddr, "ssl:") { + // Get the OVN SSL keys from the daemon config. + sslCACert, sslClientCert, sslClientKey := s.GlobalConfig.NetworkOVNSSL() + + // Fallback to filesystem keys. + if sslCACert == "" { + content, err := os.ReadFile("/etc/ovn/ovn-central.crt") + if err != nil { + if os.IsNotExist(err) { + return nil, fmt.Errorf("OVN configured to use SSL but no SSL CA certificate defined") + } + + return nil, err + } + + sslCACert = string(content) + } + + if sslClientCert == "" { + content, err := os.ReadFile("/etc/ovn/cert_host") + if err != nil { + if os.IsNotExist(err) { + return nil, fmt.Errorf("OVN configured to use SSL but no SSL client certificate defined") + } + + return nil, err + } + + sslClientCert = string(content) + } + + if sslClientKey == "" { + content, err := os.ReadFile("/etc/ovn/key_host") + if err != nil { + if os.IsNotExist(err) { + return nil, fmt.Errorf("OVN configured to use SSL but no SSL client key defined") + } + + return nil, err + } + + sslClientKey = string(content) + } + + // Validation. + if sslClientCert == "" { + return nil, fmt.Errorf("OVN is configured to use SSL but no client certificate was found") + } + + if sslClientKey == "" { + return nil, fmt.Errorf("OVN is configured to use SSL but no client key was found") + } + + // Prepare the client. + clientCert, err := tls.X509KeyPair([]byte(sslClientCert), []byte(sslClientKey)) + if err != nil { + return nil, err + } + + tlsConfig := &tls.Config{ + Certificates: []tls.Certificate{clientCert}, + InsecureSkipVerify: true, + } + + // Add CA check if provided. + if sslCACert != "" { + tlsCAder, _ := pem.Decode([]byte(sslCACert)) + if tlsCAder == nil { + return nil, fmt.Errorf("Couldn't parse CA certificate") + } + + tlsCAcert, err := x509.ParseCertificate(tlsCAder.Bytes) + if err != nil { + return nil, err + } + + tlsCAcert.IsCA = true + tlsCAcert.KeyUsage = x509.KeyUsageCertSign + + clientCAPool := x509.NewCertPool() + clientCAPool.AddCert(tlsCAcert) + + tlsConfig.VerifyPeerCertificate = func(rawCerts [][]byte, chains [][]*x509.Certificate) error { + if len(rawCerts) < 1 { + return fmt.Errorf("Missing server certificate") + } + + // Load the chain. + roots := x509.NewCertPool() + for _, rawCert := range rawCerts { + cert, _ := x509.ParseCertificate(rawCert) + if cert != nil { + roots.AddCert(cert) + } + } + + // Load the main server certificate. + cert, _ := x509.ParseCertificate(rawCerts[0]) + if cert == nil { + return fmt.Errorf("Bad server certificate") + } + + // Validate. + opts := x509.VerifyOptions{ + Roots: roots, + } + + _, err := cert.Verify(opts) + return err + } + } + + // Add the TLS config to the client. + options = append(options, ovsdbClient.WithTLSConfig(tlsConfig)) + } + + // Connect to OVSDB. + ovn, err := ovsdbClient.NewOVSDBClient(dbSchema, options...) + if err != nil { + return nil, err + } + + err = ovn.Connect(context.TODO()) + if err != nil { + return nil, err + } + + err = ovn.Echo(context.TODO()) + if err != nil { + return nil, err + } + + monitorCookie, err := ovn.MonitorAll(context.TODO()) + if err != nil { + return nil, err + } + + // Create the SB struct. + client := &SB{ + client: ovn, + cookie: monitorCookie, + } + + // Set finalizer to stop the monitor. + runtime.SetFinalizer(client, func(o *SB) { + _ = ovn.MonitorCancel(context.Background(), o.cookie) + }) + + return client, nil +} From c75283b882bf7294bec012abc6d48dcc581716e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Tue, 19 Dec 2023 14:20:27 -0500 Subject: [PATCH 28/38] incusd/network/ovn: Move GetLogicalRouterPortActiveChassisHostname to SB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- internal/server/network/ovn/ovn_actions.go | 17 -------- internal/server/network/ovn/ovn_sb_actions.go | 39 +++++++++++++++++++ 2 files changed, 39 insertions(+), 17 deletions(-) create mode 100644 internal/server/network/ovn/ovn_sb_actions.go diff --git a/internal/server/network/ovn/ovn_actions.go b/internal/server/network/ovn/ovn_actions.go index 4a9e6403881..32762d4f9ad 100644 --- a/internal/server/network/ovn/ovn_actions.go +++ b/internal/server/network/ovn/ovn_actions.go @@ -2264,20 +2264,3 @@ func (o *OVN) GetHardwareAddress(ovnRouterPort OVNRouterPort) (string, error) { return strings.TrimSpace(hwaddr), nil } - -// GetLogicalRouterPortActiveChassisHostname gets the hostname of the chassis managing the logical router port. -func (o *OVN) GetLogicalRouterPortActiveChassisHostname(ovnRouterPort OVNRouterPort) (string, error) { - // Get the chassis ID from port bindings where the logical port is a chassis redirect (prepended "cr-") of the logical router port name. - filter := fmt.Sprintf("logical_port=cr-%s", ovnRouterPort) - chassisID, err := o.sbctl("--no-headings", "--columns=chassis", "--data=bare", "--format=csv", "find", "Port_Binding", filter) - if err != nil { - return "", err - } - - hostname, err := o.sbctl("get", "Chassis", strings.TrimSpace(chassisID), "hostname") - if err != nil { - return "", err - } - - return strings.TrimSpace(hostname), err -} diff --git a/internal/server/network/ovn/ovn_sb_actions.go b/internal/server/network/ovn/ovn_sb_actions.go new file mode 100644 index 00000000000..663068da032 --- /dev/null +++ b/internal/server/network/ovn/ovn_sb_actions.go @@ -0,0 +1,39 @@ +package ovn + +import ( + "context" + "fmt" + + ovnSB "github.com/lxc/incus/internal/server/network/ovn/schema/ovn-sb" +) + +// GetLogicalRouterPortActiveChassisHostname gets the hostname of the chassis managing the logical router port. +func (o *SB) GetLogicalRouterPortActiveChassisHostname(ovnRouterPort OVNRouterPort) (string, error) { + ctx := context.TODO() + + // Look for the port binding. + pb := &ovnSB.PortBinding{ + LogicalPort: fmt.Sprintf("cr-%s", ovnRouterPort), + } + + err := o.client.Get(ctx, pb) + if err != nil { + return "", err + } + + if pb.Chassis == nil { + return "", fmt.Errorf("No chassis found") + } + + // Get the associated chassis. + chassis := &ovnSB.Chassis{ + UUID: *pb.Chassis, + } + + err = o.client.Get(ctx, chassis) + if err != nil { + return "", err + } + + return chassis.Hostname, nil +} From 3b917ecfc544f6dba1df9c3d35e4ef0531f5569d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Tue, 19 Dec 2023 17:20:23 -0500 Subject: [PATCH 29/38] incusd/network: Update for GetLogicalRouterPortActiveChassisHostname MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- internal/server/network/driver_ovn.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/internal/server/network/driver_ovn.go b/internal/server/network/driver_ovn.go index ef1442b7bc1..2dab373585c 100644 --- a/internal/server/network/driver_ovn.go +++ b/internal/server/network/driver_ovn.go @@ -143,7 +143,12 @@ func (n *ovn) State() (*api.NetworkState, error) { } } - chassis, err := ovnnb.GetLogicalRouterPortActiveChassisHostname(n.getRouterExtPortName()) + ovnsb, err := networkOVN.NewSB(n.state) + if err != nil { + return nil, err + } + + chassis, err := ovnsb.GetLogicalRouterPortActiveChassisHostname(n.getRouterExtPortName()) if err != nil { return nil, err } From fb633b225f2e5c7c5749ecb13ce7e838c9d39add Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Tue, 19 Dec 2023 18:19:04 -0500 Subject: [PATCH 30/38] incusd/network/ovn: Replace OVN struct with NB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- .../server/network/ovn/{ovn.go => ovn_nb.go} | 231 ++++++------------ .../ovn/{ovn_actions.go => ovn_nb_actions.go} | 160 ++++++------ 2 files changed, 148 insertions(+), 243 deletions(-) rename internal/server/network/ovn/{ovn.go => ovn_nb.go} (50%) rename internal/server/network/ovn/{ovn_actions.go => ovn_nb_actions.go} (89%) diff --git a/internal/server/network/ovn/ovn.go b/internal/server/network/ovn/ovn_nb.go similarity index 50% rename from internal/server/network/ovn/ovn.go rename to internal/server/network/ovn/ovn_nb.go index 7d9f0a69804..b5b75b7eeec 100644 --- a/internal/server/network/ovn/ovn.go +++ b/internal/server/network/ovn/ovn_nb.go @@ -7,40 +7,59 @@ import ( "encoding/pem" "fmt" "os" + "runtime" "strings" - "sync" "github.com/go-logr/logr" ovsdbClient "github.com/ovn-org/libovsdb/client" - ovsdbModel "github.com/ovn-org/libovsdb/model" "github.com/lxc/incus/internal/linux" ovnNB "github.com/lxc/incus/internal/server/network/ovn/schema/ovn-nb" - ovnSB "github.com/lxc/incus/internal/server/network/ovn/schema/ovn-sb" - "github.com/lxc/incus/internal/server/network/ovs" "github.com/lxc/incus/internal/server/state" "github.com/lxc/incus/shared/subprocess" ) -// NewOVN initialises new OVN client wrapper with the connection set in network.ovn.northbound_connection config. -func NewOVN(s *state.State) (*OVN, error) { - // Get database connection strings. - nbConnection := s.GlobalConfig.NetworkOVNNorthboundConnection() - sbConnection, err := ovs.NewVSwitch().OVNSouthboundDBRemoteAddress() +// NB client. +type NB struct { + client ovsdbClient.Client + cookie ovsdbClient.MonitorCookie + + // For nbctl command calls. + dbAddr string + sslCACert string + sslClientCert string + sslClientKey string +} + +// NewNB initialises new OVN client for Northbound operations. +func NewNB(s *state.State) (*NB, error) { + // Get database connection string. + dbAddr := s.GlobalConfig.NetworkOVNNorthboundConnection() + + // Create the NB struct. + client := &NB{ + dbAddr: dbAddr, + } + + // Prepare the OVSDB client. + dbSchema, err := ovnNB.FullDatabaseModel() if err != nil { - return nil, fmt.Errorf("Failed to get OVN southbound connection string: %w", err) + return nil, err } - // Create the OVN struct. - client := &OVN{ - nbDBAddr: nbConnection, - sbDBAddr: sbConnection, + discard := logr.Discard() + + options := []ovsdbClient.Option{ovsdbClient.WithLogger(&discard)} + for _, entry := range strings.Split(dbAddr, ",") { + options = append(options, ovsdbClient.WithEndpoint(entry)) } - // If using SSL, then get the CA and client key pair. - if strings.Contains(nbConnection, "ssl:") { + // Handle SSL. + if strings.Contains(dbAddr, "ssl:") { + // Get the OVN SSL keys from the daemon config. sslCACert, sslClientCert, sslClientKey := s.GlobalConfig.NetworkOVNSSL() + // Fallback to filesystem keys. if sslCACert == "" { content, err := os.ReadFile("/etc/ovn/ovn-central.crt") if err != nil { @@ -80,86 +99,19 @@ func NewOVN(s *state.State) (*OVN, error) { sslClientKey = string(content) } - client.sslCACert = sslCACert - client.sslClientCert = sslClientCert - client.sslClientKey = sslClientKey - } - - return client, nil -} - -// OVN command wrapper. -type OVN struct { - mu sync.Mutex - - nbDBAddr string - sbDBAddr string - - sslCACert string - sslClientCert string - sslClientKey string - - ovsdbClient map[ovnDatabase]*ovnClient -} - -type ovnClient struct { - client ovsdbClient.Client - group sync.WaitGroup -} - -// ovnDatabase represents the OVN database to connect to. -type ovnDatabase string - -const ovnDatabaseNorthbound = ovnDatabase("nortbound") -const ovnDatabaseSouthbound = ovnDatabase("southbound") - -func (o *OVN) client(database ovnDatabase) (ovsdbClient.Client, func(), error) { - // Check if we already have a client. - o.mu.Lock() - defer o.mu.Unlock() - client, ok := o.ovsdbClient[database] - if ok { - client.group.Add(1) - return client.client, func() { client.group.Done() }, nil - } - - // Figure out the database address and schema. - var dbAddr string - var dbSchema ovsdbModel.ClientDBModel - - if database == ovnDatabaseNorthbound { - var err error - dbAddr = o.getNorthboundDB() - - dbSchema, err = ovnNB.FullDatabaseModel() - if err != nil { - return nil, nil, err + // Validation. + if sslClientCert == "" { + return nil, fmt.Errorf("OVN is configured to use SSL but no client certificate was found") } - } else if database == ovnDatabaseSouthbound { - var err error - dbAddr = o.getSouthboundDB() - dbSchema, err = ovnSB.FullDatabaseModel() - if err != nil { - return nil, nil, err + if sslClientKey == "" { + return nil, fmt.Errorf("OVN is configured to use SSL but no client key was found") } - } else { - return nil, nil, fmt.Errorf("Unsupported database type %q", database) - } - - // Prepare the client. - discard := logr.Discard() - - options := []ovsdbClient.Option{ovsdbClient.WithLogger(&discard)} - for _, entry := range strings.Split(dbAddr, ",") { - options = append(options, ovsdbClient.WithEndpoint(entry)) - } - // Handle SSL. - if strings.Contains(dbAddr, "ssl:") { - clientCert, err := tls.X509KeyPair([]byte(o.sslClientCert), []byte(o.sslClientKey)) + // Prepare the client. + clientCert, err := tls.X509KeyPair([]byte(sslClientCert), []byte(sslClientKey)) if err != nil { - return nil, nil, err + return nil, err } tlsConfig := &tls.Config{ @@ -167,16 +119,16 @@ func (o *OVN) client(database ovnDatabase) (ovsdbClient.Client, func(), error) { InsecureSkipVerify: true, } - // If provided with a CA certificate, setup a validator for the cert chain (but not the name). - if o.sslCACert != "" { - tlsCAder, _ := pem.Decode([]byte(o.sslCACert)) + // Add CA check if provided. + if sslCACert != "" { + tlsCAder, _ := pem.Decode([]byte(sslCACert)) if tlsCAder == nil { - return nil, nil, fmt.Errorf("Couldn't parse CA certificate") + return nil, fmt.Errorf("Couldn't parse CA certificate") } tlsCAcert, err := x509.ParseCertificate(tlsCAder.Bytes) if err != nil { - return nil, nil, err + return nil, err } tlsCAcert.IsCA = true @@ -215,95 +167,56 @@ func (o *OVN) client(database ovnDatabase) (ovsdbClient.Client, func(), error) { } } + // Add the TLS config to the client. options = append(options, ovsdbClient.WithTLSConfig(tlsConfig)) + + // Fill the fields need for the CLI calls. + client.sslCACert = sslCACert + client.sslClientCert = sslClientCert + client.sslClientKey = sslClientKey } + // Connect to OVSDB. ovn, err := ovsdbClient.NewOVSDBClient(dbSchema, options...) if err != nil { - return nil, nil, err + return nil, err } - err = ovn.Connect(context.Background()) + err = ovn.Connect(context.TODO()) if err != nil { - return nil, nil, err + return nil, err } err = ovn.Echo(context.TODO()) if err != nil { - return nil, nil, err + return nil, err } monitorCookie, err := ovn.MonitorAll(context.TODO()) if err != nil { - return nil, nil, err - } - - dbClient := &ovnClient{ - client: ovn, - group: sync.WaitGroup{}, - } - - dbClient.group.Add(1) - - go func() { - dbClient.group.Wait() - _ = ovn.MonitorCancel(context.TODO(), monitorCookie) - }() - - o.ovsdbClient[database] = dbClient - - return ovn, func() { dbClient.group.Done() }, nil -} - -// getNorthboundDB returns connection string to use for northbound database. -func (o *OVN) getNorthboundDB() string { - if o.nbDBAddr == "" { - return "unix:/var/run/ovn/ovnnb_db.sock" + return nil, err } - return o.nbDBAddr -} + // Add the client to the struct. + client.client = ovn + client.cookie = monitorCookie -// getSouthboundDB returns connection string to use for northbound database. -func (o *OVN) getSouthboundDB() string { - if o.sbDBAddr == "" { - return "unix:/var/run/ovn/ovnsb_db.sock" - } + // Set finalizer to stop the monitor. + runtime.SetFinalizer(client, func(o *NB) { + _ = ovn.MonitorCancel(context.Background(), o.cookie) + }) - return o.sbDBAddr -} - -// sbctl executes ovn-sbctl with arguments to connect to wrapper's southbound database. -func (o *OVN) sbctl(args ...string) (string, error) { - return o.xbctl(ovnDatabaseSouthbound, args...) + return client, nil } // nbctl executes ovn-nbctl with arguments to connect to wrapper's northbound database. -func (o *OVN) nbctl(args ...string) (string, error) { - return o.xbctl(ovnDatabaseNorthbound, append([]string{"--wait=sb"}, args...)...) -} - -// xbctl optionally executes either ovn-nbctl or ovn-sbctl with arguments to connect to wrapper's northbound or southbound database. -func (o *OVN) xbctl(database ovnDatabase, extraArgs ...string) (string, error) { - // Figure out the command. - var dbAddr string - var cmd string - if database == ovnDatabaseNorthbound { - dbAddr = o.getNorthboundDB() - cmd = "ovn-nbctl" - } else if database == ovnDatabaseSouthbound { - dbAddr = o.getSouthboundDB() - cmd = "ovn-sbctl" - } else { - return "", fmt.Errorf("Unsupported database type %q", database) - } - +func (o *NB) nbctl(extraArgs ...string) (string, error) { // Figure out args. - args := []string{"--timeout=10", "--db", dbAddr} + args := []string{"--timeout=10", "--db", o.dbAddr} // Handle SSL args. files := []*os.File{} - if strings.Contains(dbAddr, "ssl:") { + if strings.Contains(o.dbAddr, "ssl:") { // Handle client certificate. clientCertFile, err := linux.CreateMemfd([]byte(o.sslClientCert)) if err != nil { @@ -339,5 +252,5 @@ func (o *OVN) xbctl(database ovnDatabase, extraArgs ...string) (string, error) { } args = append(args, extraArgs...) - return subprocess.RunCommandInheritFds(context.Background(), files, cmd, args...) + return subprocess.RunCommandInheritFds(context.Background(), files, "ovn-nbctl", args...) } diff --git a/internal/server/network/ovn/ovn_actions.go b/internal/server/network/ovn/ovn_nb_actions.go similarity index 89% rename from internal/server/network/ovn/ovn_actions.go rename to internal/server/network/ovn/ovn_nb_actions.go index 32762d4f9ad..c871647fba5 100644 --- a/internal/server/network/ovn/ovn_actions.go +++ b/internal/server/network/ovn/ovn_nb_actions.go @@ -180,7 +180,7 @@ type OVNRouterPeering struct { } // LogicalRouterAdd adds a named logical router. -func (o *OVN) LogicalRouterAdd(routerName OVNRouter, mayExist bool) error { +func (o *NB) LogicalRouterAdd(routerName OVNRouter, mayExist bool) error { args := []string{} if mayExist { @@ -196,7 +196,7 @@ func (o *OVN) LogicalRouterAdd(routerName OVNRouter, mayExist bool) error { } // LogicalRouterDelete deletes a named logical router. -func (o *OVN) LogicalRouterDelete(routerName OVNRouter) error { +func (o *NB) LogicalRouterDelete(routerName OVNRouter) error { _, err := o.nbctl("--if-exists", "lr-del", string(routerName)) if err != nil { return err @@ -206,7 +206,7 @@ func (o *OVN) LogicalRouterDelete(routerName OVNRouter) error { } // LogicalRouterSNATAdd adds an SNAT rule to a logical router to translate packets from intNet to extIP. -func (o *OVN) LogicalRouterSNATAdd(routerName OVNRouter, intNet *net.IPNet, extIP net.IP, mayExist bool) error { +func (o *NB) LogicalRouterSNATAdd(routerName OVNRouter, intNet *net.IPNet, extIP net.IP, mayExist bool) error { args := []string{} if mayExist { @@ -222,7 +222,7 @@ func (o *OVN) LogicalRouterSNATAdd(routerName OVNRouter, intNet *net.IPNet, extI } // LogicalRouterDNATSNATDeleteAll deletes all DNAT_AND_SNAT rules from a logical router. -func (o *OVN) LogicalRouterDNATSNATDeleteAll(routerName OVNRouter) error { +func (o *NB) LogicalRouterDNATSNATDeleteAll(routerName OVNRouter) error { _, err := o.nbctl("--if-exists", "lr-nat-del", string(routerName), "dnat_and_snat") if err != nil { return err @@ -232,7 +232,7 @@ func (o *OVN) LogicalRouterDNATSNATDeleteAll(routerName OVNRouter) error { } // LogicalRouterSNATDeleteAll deletes all SNAT rules from a logical router. -func (o *OVN) LogicalRouterSNATDeleteAll(routerName OVNRouter) error { +func (o *NB) LogicalRouterSNATDeleteAll(routerName OVNRouter) error { _, err := o.nbctl("--if-exists", "lr-nat-del", string(routerName), "snat") if err != nil { return err @@ -242,7 +242,7 @@ func (o *OVN) LogicalRouterSNATDeleteAll(routerName OVNRouter) error { } // LogicalRouterDNATSNATAdd adds a DNAT_AND_SNAT rule to a logical router to translate packets from extIP to intIP. -func (o *OVN) LogicalRouterDNATSNATAdd(routerName OVNRouter, extIP net.IP, intIP net.IP, stateless bool, mayExist bool) error { +func (o *NB) LogicalRouterDNATSNATAdd(routerName OVNRouter, extIP net.IP, intIP net.IP, stateless bool, mayExist bool) error { if mayExist { // There appears to be a bug in ovn-nbctl where running lr-nat-del as part of the same command as // lr-nat-add doesn't take account the changes by lr-nat-del, and so you can end up with errors @@ -270,7 +270,7 @@ func (o *OVN) LogicalRouterDNATSNATAdd(routerName OVNRouter, extIP net.IP, intIP } // LogicalRouterDNATSNATDelete deletes a DNAT_AND_SNAT rule from a logical router. -func (o *OVN) LogicalRouterDNATSNATDelete(routerName OVNRouter, extIPs ...net.IP) error { +func (o *NB) LogicalRouterDNATSNATDelete(routerName OVNRouter, extIPs ...net.IP) error { args := []string{} for _, extIP := range extIPs { @@ -290,7 +290,7 @@ func (o *OVN) LogicalRouterDNATSNATDelete(routerName OVNRouter, extIPs ...net.IP } // LogicalRouterRouteAdd adds a static route to the logical router. -func (o *OVN) LogicalRouterRouteAdd(routerName OVNRouter, mayExist bool, routes ...OVNRouterRoute) error { +func (o *NB) LogicalRouterRouteAdd(routerName OVNRouter, mayExist bool, routes ...OVNRouterRoute) error { args := []string{} for _, route := range routes { @@ -326,7 +326,7 @@ func (o *OVN) LogicalRouterRouteAdd(routerName OVNRouter, mayExist bool, routes } // LogicalRouterRouteDelete deletes a static route from the logical router. -func (o *OVN) LogicalRouterRouteDelete(routerName OVNRouter, prefixes ...net.IPNet) error { +func (o *NB) LogicalRouterRouteDelete(routerName OVNRouter, prefixes ...net.IPNet) error { args := []string{} // Delete specific destination routes on router. @@ -347,7 +347,7 @@ func (o *OVN) LogicalRouterRouteDelete(routerName OVNRouter, prefixes ...net.IPN } // LogicalRouterPortAdd adds a named logical router port to a logical router. -func (o *OVN) LogicalRouterPortAdd(routerName OVNRouter, portName OVNRouterPort, mac net.HardwareAddr, gatewayMTU uint32, ipAddr []*net.IPNet, mayExist bool) error { +func (o *NB) LogicalRouterPortAdd(routerName OVNRouter, portName OVNRouterPort, mac net.HardwareAddr, gatewayMTU uint32, ipAddr []*net.IPNet, mayExist bool) error { if mayExist { // Check if it exists and update addresses. _, err := o.nbctl("list", "Logical_Router_Port", string(portName)) @@ -389,7 +389,7 @@ func (o *OVN) LogicalRouterPortAdd(routerName OVNRouter, portName OVNRouterPort, } // LogicalRouterPortDelete deletes a named logical router port from a logical router. -func (o *OVN) LogicalRouterPortDelete(portName OVNRouterPort) error { +func (o *NB) LogicalRouterPortDelete(portName OVNRouterPort) error { _, err := o.nbctl("--if-exists", "lrp-del", string(portName)) if err != nil { return err @@ -399,7 +399,7 @@ func (o *OVN) LogicalRouterPortDelete(portName OVNRouterPort) error { } // LogicalRouterPortSetIPv6Advertisements sets the IPv6 router advertisement options on a router port. -func (o *OVN) LogicalRouterPortSetIPv6Advertisements(portName OVNRouterPort, opts *OVNIPv6RAOpts) error { +func (o *NB) LogicalRouterPortSetIPv6Advertisements(portName OVNRouterPort, opts *OVNIPv6RAOpts) error { args := []string{"set", "logical_router_port", string(portName), fmt.Sprintf("ipv6_ra_configs:send_periodic=%t", opts.SendPeriodic), } @@ -461,7 +461,7 @@ func (o *OVN) LogicalRouterPortSetIPv6Advertisements(portName OVNRouterPort, opt } // LogicalRouterPortDeleteIPv6Advertisements removes the IPv6 RA announcement settings from a router port. -func (o *OVN) LogicalRouterPortDeleteIPv6Advertisements(portName OVNRouterPort) error { +func (o *NB) LogicalRouterPortDeleteIPv6Advertisements(portName OVNRouterPort) error { // Delete IPv6 Router Advertisements. _, err := o.nbctl("clear", "logical_router_port", string(portName), "ipv6_ra_configs") if err != nil { @@ -472,7 +472,7 @@ func (o *OVN) LogicalRouterPortDeleteIPv6Advertisements(portName OVNRouterPort) } // LogicalRouterPortLinkChassisGroup links a logical router port to a HA chassis group. -func (o *OVN) LogicalRouterPortLinkChassisGroup(portName OVNRouterPort, haChassisGroupName OVNChassisGroup) error { +func (o *NB) LogicalRouterPortLinkChassisGroup(portName OVNRouterPort, haChassisGroupName OVNChassisGroup) error { chassisGroupID, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid", "find", "ha_chassis_group", fmt.Sprintf("name=%s", haChassisGroupName)) if err != nil { return err @@ -494,7 +494,7 @@ func (o *OVN) LogicalRouterPortLinkChassisGroup(portName OVNRouterPort, haChassi // LogicalSwitchAdd adds a named logical switch. // If mayExist is true, then an existing resource of the same name is not treated as an error. -func (o *OVN) LogicalSwitchAdd(switchName OVNSwitch, mayExist bool) error { +func (o *NB) LogicalSwitchAdd(switchName OVNSwitch, mayExist bool) error { args := []string{} if mayExist { @@ -511,7 +511,7 @@ func (o *OVN) LogicalSwitchAdd(switchName OVNSwitch, mayExist bool) error { } // LogicalSwitchDelete deletes a named logical switch. -func (o *OVN) LogicalSwitchDelete(switchName OVNSwitch) error { +func (o *NB) LogicalSwitchDelete(switchName OVNSwitch) error { args := []string{"--if-exists", "ls-del", string(switchName)} assocPortGroups, err := o.logicalSwitchFindAssociatedPortGroups(switchName) @@ -555,7 +555,7 @@ func (o *OVN) LogicalSwitchDelete(switchName OVNSwitch) error { } // logicalSwitchFindAssociatedPortGroups finds the port groups that are associated to the switch specified. -func (o *OVN) logicalSwitchFindAssociatedPortGroups(switchName OVNSwitch) ([]OVNPortGroup, error) { +func (o *NB) logicalSwitchFindAssociatedPortGroups(switchName OVNSwitch) ([]OVNPortGroup, error) { output, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=name", "find", "port_group", fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName), ) @@ -574,7 +574,7 @@ func (o *OVN) logicalSwitchFindAssociatedPortGroups(switchName OVNSwitch) ([]OVN } // logicalSwitchParseExcludeIPs parses the ips into OVN exclude_ips format. -func (o *OVN) logicalSwitchParseExcludeIPs(ips []iprange.Range) ([]string, error) { +func (o *NB) logicalSwitchParseExcludeIPs(ips []iprange.Range) ([]string, error) { excludeIPs := make([]string, 0, len(ips)) for _, v := range ips { if v.Start == nil || v.Start.To4() == nil { @@ -594,7 +594,7 @@ func (o *OVN) logicalSwitchParseExcludeIPs(ips []iprange.Range) ([]string, error } // LogicalSwitchSetIPAllocation sets the IP allocation config on the logical switch. -func (o *OVN) LogicalSwitchSetIPAllocation(switchName OVNSwitch, opts *OVNIPAllocationOpts) error { +func (o *NB) LogicalSwitchSetIPAllocation(switchName OVNSwitch, opts *OVNIPAllocationOpts) error { var removeOtherConfigKeys []string args := []string{"set", "logical_switch", string(switchName)} @@ -642,7 +642,7 @@ func (o *OVN) LogicalSwitchSetIPAllocation(switchName OVNSwitch, opts *OVNIPAllo } // LogicalSwitchDHCPv4RevervationsSet sets the DHCPv4 IP reservations. -func (o *OVN) LogicalSwitchDHCPv4RevervationsSet(switchName OVNSwitch, reservedIPs []iprange.Range) error { +func (o *NB) LogicalSwitchDHCPv4RevervationsSet(switchName OVNSwitch, reservedIPs []iprange.Range) error { var removeOtherConfigKeys []string args := []string{"set", "logical_switch", string(switchName)} @@ -678,7 +678,7 @@ func (o *OVN) LogicalSwitchDHCPv4RevervationsSet(switchName OVNSwitch, reservedI } // LogicalSwitchDHCPv4RevervationsGet gets the DHCPv4 IP reservations. -func (o *OVN) LogicalSwitchDHCPv4RevervationsGet(switchName OVNSwitch) ([]iprange.Range, error) { +func (o *NB) LogicalSwitchDHCPv4RevervationsGet(switchName OVNSwitch) ([]iprange.Range, error) { excludeIPsRaw, err := o.nbctl("--if-exists", "get", "logical_switch", string(switchName), "other_config:exclude_ips") if err != nil { return nil, err @@ -729,7 +729,7 @@ func (o *OVN) LogicalSwitchDHCPv4RevervationsGet(switchName OVNSwitch) ([]iprang // LogicalSwitchDHCPv4OptionsSet creates or updates a DHCPv4 option set associated with the specified switchName // and subnet. If uuid is non-empty then the record that exists with that ID is updated, otherwise a new record // is created. -func (o *OVN) LogicalSwitchDHCPv4OptionsSet(switchName OVNSwitch, uuid OVNDHCPOptionsUUID, subnet *net.IPNet, opts *OVNDHCPv4Opts) error { +func (o *NB) LogicalSwitchDHCPv4OptionsSet(switchName OVNSwitch, uuid OVNDHCPOptionsUUID, subnet *net.IPNet, opts *OVNDHCPv4Opts) error { var err error if uuid != "" { @@ -801,7 +801,7 @@ func (o *OVN) LogicalSwitchDHCPv4OptionsSet(switchName OVNSwitch, uuid OVNDHCPOp // LogicalSwitchDHCPv6OptionsSet creates or updates a DHCPv6 option set associated with the specified switchName // and subnet. If uuid is non-empty then the record that exists with that ID is updated, otherwise a new record // is created. -func (o *OVN) LogicalSwitchDHCPv6OptionsSet(switchName OVNSwitch, uuid OVNDHCPOptionsUUID, subnet *net.IPNet, opts *OVNDHCPv6Opts) error { +func (o *NB) LogicalSwitchDHCPv6OptionsSet(switchName OVNSwitch, uuid OVNDHCPOptionsUUID, subnet *net.IPNet, opts *OVNDHCPv6Opts) error { var err error if uuid != "" { @@ -857,7 +857,7 @@ func (o *OVN) LogicalSwitchDHCPv6OptionsSet(switchName OVNSwitch, uuid OVNDHCPOp } // LogicalSwitchDHCPOptionsGet retrieves the existing DHCP options defined for a logical switch. -func (o *OVN) LogicalSwitchDHCPOptionsGet(switchName OVNSwitch) ([]OVNDHCPOptsSet, error) { +func (o *NB) LogicalSwitchDHCPOptionsGet(switchName OVNSwitch) ([]OVNDHCPOptsSet, error) { output, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid,cidr", "find", "dhcp_options", fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName), ) @@ -891,7 +891,7 @@ func (o *OVN) LogicalSwitchDHCPOptionsGet(switchName OVNSwitch) ([]OVNDHCPOptsSe } // LogicalSwitchDHCPOptionsDelete deletes the specified DHCP options defined for a switch. -func (o *OVN) LogicalSwitchDHCPOptionsDelete(switchName OVNSwitch, uuids ...OVNDHCPOptionsUUID) error { +func (o *NB) LogicalSwitchDHCPOptionsDelete(switchName OVNSwitch, uuids ...OVNDHCPOptionsUUID) error { args := []string{} for _, uuid := range uuids { @@ -911,7 +911,7 @@ func (o *OVN) LogicalSwitchDHCPOptionsDelete(switchName OVNSwitch, uuids ...OVND } // logicalSwitchDNSRecordsDelete deletes any DNS records defined for a switch. -func (o *OVN) logicalSwitchDNSRecordsDelete(switchName OVNSwitch) error { +func (o *NB) logicalSwitchDNSRecordsDelete(switchName OVNSwitch) error { uuids, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid", "find", "dns", fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName), ) @@ -940,7 +940,7 @@ func (o *OVN) logicalSwitchDNSRecordsDelete(switchName OVNSwitch) error { } // LogicalSwitchSetACLRules applies a set of rules to the specified logical switch. Any existing rules are removed. -func (o *OVN) LogicalSwitchSetACLRules(switchName OVNSwitch, aclRules ...OVNACLRule) error { +func (o *NB) LogicalSwitchSetACLRules(switchName OVNSwitch, aclRules ...OVNACLRule) error { // Remove any existing rules assigned to the entity. args := []string{"clear", "logical_switch", string(switchName), "acls"} @@ -960,7 +960,7 @@ func (o *OVN) LogicalSwitchSetACLRules(switchName OVNSwitch, aclRules ...OVNACLR } // logicalSwitchPortACLRules returns the ACL rule UUIDs belonging to a logical switch port. -func (o *OVN) logicalSwitchPortACLRules(portName OVNSwitchPort) ([]string, error) { +func (o *NB) logicalSwitchPortACLRules(portName OVNSwitchPort) ([]string, error) { // Remove any existing rules assigned to the entity. output, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid", "find", "acl", fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitchPort, string(portName)), @@ -976,7 +976,7 @@ func (o *OVN) logicalSwitchPortACLRules(portName OVNSwitchPort) ([]string, error // LogicalSwitchPorts returns a map of logical switch ports (name and UUID) for a switch. // Includes non-instance ports, such as the router port. -func (o *OVN) LogicalSwitchPorts(switchName OVNSwitch) (map[OVNSwitchPort]OVNSwitchPortUUID, error) { +func (o *NB) LogicalSwitchPorts(switchName OVNSwitch) (map[OVNSwitchPort]OVNSwitchPortUUID, error) { output, err := o.nbctl("lsp-list", string(switchName)) if err != nil { return nil, err @@ -1002,7 +1002,7 @@ func (o *OVN) LogicalSwitchPorts(switchName OVNSwitch) (map[OVNSwitchPort]OVNSwi } // LogicalSwitchIPs returns a list of IPs associated to each port connected to switch. -func (o *OVN) LogicalSwitchIPs(switchName OVNSwitch) (map[OVNSwitchPort][]net.IP, error) { +func (o *NB) LogicalSwitchIPs(switchName OVNSwitch) (map[OVNSwitchPort][]net.IP, error) { output, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=name,addresses,dynamic_addresses", "find", "logical_switch_port", fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, switchName), ) @@ -1035,7 +1035,7 @@ func (o *OVN) LogicalSwitchIPs(switchName OVNSwitch) (map[OVNSwitchPort][]net.IP } // LogicalSwitchPortUUID returns the logical switch port UUID or empty string if port doesn't exist. -func (o *OVN) LogicalSwitchPortUUID(portName OVNSwitchPort) (OVNSwitchPortUUID, error) { +func (o *NB) LogicalSwitchPortUUID(portName OVNSwitchPort) (OVNSwitchPortUUID, error) { portInfo, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid,name", "find", "logical_switch_port", fmt.Sprintf("name=%s", string(portName)), ) @@ -1055,7 +1055,7 @@ func (o *OVN) LogicalSwitchPortUUID(portName OVNSwitchPort) (OVNSwitchPortUUID, // LogicalSwitchPortAdd adds a named logical switch port to a logical switch, and sets options if provided. // If mayExist is true, then an existing resource of the same name is not treated as an error. -func (o *OVN) LogicalSwitchPortAdd(switchName OVNSwitch, portName OVNSwitchPort, opts *OVNSwitchPortOpts, mayExist bool) error { +func (o *NB) LogicalSwitchPortAdd(switchName OVNSwitch, portName OVNSwitchPort, opts *OVNSwitchPortOpts, mayExist bool) error { args := []string{} if mayExist { @@ -1112,7 +1112,7 @@ func (o *OVN) LogicalSwitchPortAdd(switchName OVNSwitch, portName OVNSwitchPort, } // LogicalSwitchPortIPs returns a list of IPs for a switch port. -func (o *OVN) LogicalSwitchPortIPs(portName OVNSwitchPort) ([]net.IP, error) { +func (o *NB) LogicalSwitchPortIPs(portName OVNSwitchPort) ([]net.IP, error) { addressesRaw, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--column=addresses,dynamic_addresses", "find", "logical_switch_port", fmt.Sprintf("name=%s", string(portName))) if err != nil { return nil, err @@ -1132,7 +1132,7 @@ func (o *OVN) LogicalSwitchPortIPs(portName OVNSwitchPort) ([]net.IP, error) { } // LogicalSwitchPortDynamicIPs returns a list of dynamc IPs for a switch port. -func (o *OVN) LogicalSwitchPortDynamicIPs(portName OVNSwitchPort) ([]net.IP, error) { +func (o *NB) LogicalSwitchPortDynamicIPs(portName OVNSwitchPort) ([]net.IP, error) { dynamicAddressesRaw, err := o.nbctl("get", "logical_switch_port", string(portName), "dynamic_addresses") if err != nil { return nil, err @@ -1164,7 +1164,7 @@ func (o *OVN) LogicalSwitchPortDynamicIPs(portName OVNSwitchPort) ([]net.IP, err } // LogicalSwitchPortLocationGet returns the last set location of a logical switch port. -func (o *OVN) LogicalSwitchPortLocationGet(portName OVNSwitchPort) (string, error) { +func (o *NB) LogicalSwitchPortLocationGet(portName OVNSwitchPort) (string, error) { location, err := o.nbctl("--if-exists", "get", "logical_switch_port", string(portName), fmt.Sprintf("external-ids:%s", ovnExtIDIncusLocation)) if err != nil { return "", err @@ -1174,7 +1174,7 @@ func (o *OVN) LogicalSwitchPortLocationGet(portName OVNSwitchPort) (string, erro } // LogicalSwitchPortOptionsSet sets the options for a logical switch port. -func (o *OVN) LogicalSwitchPortOptionsSet(portName OVNSwitchPort, options map[string]string) error { +func (o *NB) LogicalSwitchPortOptionsSet(portName OVNSwitchPort, options map[string]string) error { args := []string{"lsp-set-options", string(portName)} for key, value := range options { @@ -1191,7 +1191,7 @@ func (o *OVN) LogicalSwitchPortOptionsSet(portName OVNSwitchPort, options map[st // LogicalSwitchPortSetDNS sets up the switch port DNS records for the DNS name. // Returns the DNS record UUID, IPv4 and IPv6 addresses used for DNS records. -func (o *OVN) LogicalSwitchPortSetDNS(switchName OVNSwitch, portName OVNSwitchPort, dnsName string, dnsIPs []net.IP) (OVNDNSUUID, error) { +func (o *NB) LogicalSwitchPortSetDNS(switchName OVNSwitch, portName OVNSwitchPort, dnsName string, dnsIPs []net.IP) (OVNDNSUUID, error) { // Check if existing DNS record exists for switch port. dnsUUID, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid", "find", "dns", fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitchPort, portName), @@ -1251,7 +1251,7 @@ func (o *OVN) LogicalSwitchPortSetDNS(switchName OVNSwitch, portName OVNSwitchPo } // LogicalSwitchPortGetDNS returns the logical switch port DNS info (UUID, name and IPs). -func (o *OVN) LogicalSwitchPortGetDNS(portName OVNSwitchPort) (OVNDNSUUID, string, []net.IP, error) { +func (o *NB) LogicalSwitchPortGetDNS(portName OVNSwitchPort) (OVNDNSUUID, string, []net.IP, error) { // Get UUID and DNS IPs for a switch port in the format: ",= " output, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid,records", "find", "dns", fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitchPort, portName), @@ -1287,7 +1287,7 @@ func (o *OVN) LogicalSwitchPortGetDNS(portName OVNSwitchPort) (OVNDNSUUID, strin // logicalSwitchPortDeleteDNSAppendArgs adds the command arguments to remove DNS records from a switch port. // If destroyEntry the DNS entry record itself is also removed, otherwise it is just cleared but left in place. // Returns args with the commands added to it. -func (o *OVN) logicalSwitchPortDeleteDNSAppendArgs(args []string, switchName OVNSwitch, dnsUUID OVNDNSUUID, destroyEntry bool) []string { +func (o *NB) logicalSwitchPortDeleteDNSAppendArgs(args []string, switchName OVNSwitch, dnsUUID OVNDNSUUID, destroyEntry bool) []string { if len(args) > 0 { args = append(args, "--") } @@ -1305,7 +1305,7 @@ func (o *OVN) logicalSwitchPortDeleteDNSAppendArgs(args []string, switchName OVN // LogicalSwitchPortDeleteDNS removes DNS records from a switch port. // If destroyEntry the DNS entry record itself is also removed, otherwise it is just cleared but left in place. -func (o *OVN) LogicalSwitchPortDeleteDNS(switchName OVNSwitch, dnsUUID OVNDNSUUID, destroyEntry bool) error { +func (o *NB) LogicalSwitchPortDeleteDNS(switchName OVNSwitch, dnsUUID OVNDNSUUID, destroyEntry bool) error { // Remove DNS record association from switch, and remove DNS record entry itself. _, err := o.nbctl(o.logicalSwitchPortDeleteDNSAppendArgs(nil, switchName, dnsUUID, destroyEntry)...) if err != nil { @@ -1317,7 +1317,7 @@ func (o *OVN) LogicalSwitchPortDeleteDNS(switchName OVNSwitch, dnsUUID OVNDNSUUI // logicalSwitchPortDeleteAppendArgs adds the commands to delete the specified logical switch port. // Returns args with the commands added to it. -func (o *OVN) logicalSwitchPortDeleteAppendArgs(args []string, portName OVNSwitchPort) []string { +func (o *NB) logicalSwitchPortDeleteAppendArgs(args []string, portName OVNSwitchPort) []string { if len(args) > 0 { args = append(args, "--") } @@ -1328,7 +1328,7 @@ func (o *OVN) logicalSwitchPortDeleteAppendArgs(args []string, portName OVNSwitc } // LogicalSwitchPortDelete deletes a named logical switch port. -func (o *OVN) LogicalSwitchPortDelete(portName OVNSwitchPort) error { +func (o *NB) LogicalSwitchPortDelete(portName OVNSwitchPort) error { _, err := o.nbctl(o.logicalSwitchPortDeleteAppendArgs(nil, portName)...) if err != nil { return err @@ -1338,7 +1338,7 @@ func (o *OVN) LogicalSwitchPortDelete(portName OVNSwitchPort) error { } // LogicalSwitchPortCleanup deletes the named logical switch port and its associated config. -func (o *OVN) LogicalSwitchPortCleanup(portName OVNSwitchPort, switchName OVNSwitch, switchPortGroupName OVNPortGroup, dnsUUID OVNDNSUUID) error { +func (o *NB) LogicalSwitchPortCleanup(portName OVNSwitchPort, switchName OVNSwitch, switchPortGroupName OVNPortGroup, dnsUUID OVNDNSUUID) error { // Remove any existing rules assigned to the entity. removeACLRuleUUIDs, err := o.logicalSwitchPortACLRules(portName) if err != nil { @@ -1364,7 +1364,7 @@ func (o *OVN) LogicalSwitchPortCleanup(portName OVNSwitchPort, switchName OVNSwi } // LogicalSwitchPortLinkRouter links a logical switch port to a logical router port. -func (o *OVN) LogicalSwitchPortLinkRouter(switchPortName OVNSwitchPort, routerPortName OVNRouterPort) error { +func (o *NB) LogicalSwitchPortLinkRouter(switchPortName OVNSwitchPort, routerPortName OVNRouterPort) error { // Connect logical router port to switch. _, err := o.nbctl( "lsp-set-type", string(switchPortName), "router", "--", @@ -1379,7 +1379,7 @@ func (o *OVN) LogicalSwitchPortLinkRouter(switchPortName OVNSwitchPort, routerPo } // LogicalSwitchPortLinkProviderNetwork links a logical switch port to a provider network. -func (o *OVN) LogicalSwitchPortLinkProviderNetwork(switchPortName OVNSwitchPort, extNetworkName string) error { +func (o *NB) LogicalSwitchPortLinkProviderNetwork(switchPortName OVNSwitchPort, extNetworkName string) error { // Forward any unknown MAC frames down this port. _, err := o.nbctl( "lsp-set-addresses", string(switchPortName), "unknown", "--", @@ -1395,7 +1395,7 @@ func (o *OVN) LogicalSwitchPortLinkProviderNetwork(switchPortName OVNSwitchPort, // ChassisGroupAdd adds a new HA chassis group. // If mayExist is true, then an existing resource of the same name is not treated as an error. -func (o *OVN) ChassisGroupAdd(haChassisGroupName OVNChassisGroup, mayExist bool) error { +func (o *NB) ChassisGroupAdd(haChassisGroupName OVNChassisGroup, mayExist bool) error { if mayExist { // Check if it exists (sadly ha-chassis-group-add doesn't provide --may-exist option). _, err := o.nbctl("list", "HA_Chassis_Group", string(haChassisGroupName)) @@ -1413,7 +1413,7 @@ func (o *OVN) ChassisGroupAdd(haChassisGroupName OVNChassisGroup, mayExist bool) } // ChassisGroupDelete deletes an HA chassis group. -func (o *OVN) ChassisGroupDelete(haChassisGroupName OVNChassisGroup) error { +func (o *NB) ChassisGroupDelete(haChassisGroupName OVNChassisGroup) error { // ovn-nbctl doesn't provide an "--if-exists" option for removing chassis groups. existing, err := o.nbctl("--no-headings", "--data=bare", "--colum=name", "find", "ha_chassis_group", fmt.Sprintf("name=%s", string(haChassisGroupName))) if err != nil { @@ -1432,21 +1432,13 @@ func (o *OVN) ChassisGroupDelete(haChassisGroupName OVNChassisGroup) error { } // ChassisGroupChassisAdd adds a chassis ID to an HA chassis group with the specified priority. -func (o *OVN) ChassisGroupChassisAdd(haChassisGroupName OVNChassisGroup, chassisID string, priority uint) error { - // Get the client. - client, cleanup, err := o.client(ovnDatabaseNorthbound) - if err != nil { - return err - } - - defer cleanup() - +func (o *NB) ChassisGroupChassisAdd(haChassisGroupName OVNChassisGroup, chassisID string, priority uint) error { ctx := context.TODO() operations := []ovsdb.Operation{} // Get the chassis group. haGroup := &ovnNB.HAChassisGroup{Name: string(haChassisGroupName)} - err = client.Get(ctx, haGroup) + err := o.client.Get(ctx, haGroup) if err != nil { return err } @@ -1456,7 +1448,7 @@ func (o *OVN) ChassisGroupChassisAdd(haChassisGroupName OVNChassisGroup, chassis for _, entry := range haGroup.HaChassis { chassis := &ovnNB.HAChassis{UUID: entry} - err = client.Get(ctx, chassis) + err = o.client.Get(ctx, chassis) if err != nil { return err } @@ -1475,7 +1467,7 @@ func (o *OVN) ChassisGroupChassisAdd(haChassisGroupName OVNChassisGroup, chassis Priority: int(priority), } - createOps, err := client.Create(haChassis) + createOps, err := o.client.Create(haChassis) if err != nil { return err } @@ -1484,7 +1476,7 @@ func (o *OVN) ChassisGroupChassisAdd(haChassisGroupName OVNChassisGroup, chassis // Add the HA Chassis to the group. haGroup.HaChassis = append(haGroup.HaChassis, "chassis") - updateOps, err := client.Where(haGroup).Update(haGroup) + updateOps, err := o.client.Where(haGroup).Update(haGroup) if err != nil { return err } @@ -1493,7 +1485,7 @@ func (o *OVN) ChassisGroupChassisAdd(haChassisGroupName OVNChassisGroup, chassis } else if haChassis.Priority != int(priority) { // Found but wrong priority, correct it. haChassis.Priority = int(priority) - updateOps, err := client.Where(haChassis).Update(haChassis) + updateOps, err := o.client.Where(haChassis).Update(haChassis) if err != nil { return err } @@ -1503,7 +1495,7 @@ func (o *OVN) ChassisGroupChassisAdd(haChassisGroupName OVNChassisGroup, chassis // Apply the changes. if len(operations) > 0 { - _, err := client.Transact(ctx, operations...) + _, err := o.client.Transact(ctx, operations...) if err != nil { return err } @@ -1513,7 +1505,7 @@ func (o *OVN) ChassisGroupChassisAdd(haChassisGroupName OVNChassisGroup, chassis } // ChassisGroupChassisDelete deletes a chassis ID from an HA chassis group. -func (o *OVN) ChassisGroupChassisDelete(haChassisGroupName OVNChassisGroup, chassisID string) error { +func (o *NB) ChassisGroupChassisDelete(haChassisGroupName OVNChassisGroup, chassisID string) error { // Check if chassis group exists. ovn-nbctl doesn't provide an "--if-exists" option for this. output, err := o.nbctl("--no-headings", "--data=bare", "--colum=name,ha_chassis", "find", "ha_chassis_group", fmt.Sprintf("name=%s", string(haChassisGroupName))) if err != nil { @@ -1540,7 +1532,7 @@ func (o *OVN) ChassisGroupChassisDelete(haChassisGroupName OVNChassisGroup, chas // PortGroupInfo returns the port group UUID or empty string if port doesn't exist, and whether the port group has // any ACL rules defined on it. -func (o *OVN) PortGroupInfo(portGroupName OVNPortGroup) (OVNPortGroupUUID, bool, error) { +func (o *NB) PortGroupInfo(portGroupName OVNPortGroup) (OVNPortGroupUUID, bool, error) { groupInfo, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid,name,acl", "find", "port_group", fmt.Sprintf("name=%s", string(portGroupName)), ) @@ -1561,7 +1553,7 @@ func (o *OVN) PortGroupInfo(portGroupName OVNPortGroup) (OVNPortGroupUUID, bool, } // PortGroupAdd creates a new port group and optionally adds logical switch ports to the group. -func (o *OVN) PortGroupAdd(projectID int64, portGroupName OVNPortGroup, associatedPortGroup OVNPortGroup, associatedSwitch OVNSwitch, initialPortMembers ...OVNSwitchPort) error { +func (o *NB) PortGroupAdd(projectID int64, portGroupName OVNPortGroup, associatedPortGroup OVNPortGroup, associatedSwitch OVNSwitch, initialPortMembers ...OVNSwitchPort) error { args := []string{"pg-add", string(portGroupName)} for _, portName := range initialPortMembers { args = append(args, string(portName)) @@ -1590,7 +1582,7 @@ func (o *OVN) PortGroupAdd(projectID int64, portGroupName OVNPortGroup, associat } // PortGroupDelete deletes port groups along with their ACL rules. -func (o *OVN) PortGroupDelete(portGroupNames ...OVNPortGroup) error { +func (o *NB) PortGroupDelete(portGroupNames ...OVNPortGroup) error { args := make([]string, 0) for _, portGroupName := range portGroupNames { @@ -1610,7 +1602,7 @@ func (o *OVN) PortGroupDelete(portGroupNames ...OVNPortGroup) error { } // PortGroupListByProject finds the port groups that are associated to the project ID. -func (o *OVN) PortGroupListByProject(projectID int64) ([]OVNPortGroup, error) { +func (o *NB) PortGroupListByProject(projectID int64) ([]OVNPortGroup, error) { output, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=name", "find", "port_group", fmt.Sprintf("external_ids:%s=%d", ovnExtIDIncusProjectID, projectID), ) @@ -1629,7 +1621,7 @@ func (o *OVN) PortGroupListByProject(projectID int64) ([]OVNPortGroup, error) { } // PortGroupMemberChange adds/removes logical switch ports (by UUID) to/from existing port groups. -func (o *OVN) PortGroupMemberChange(addMembers map[OVNPortGroup][]OVNSwitchPortUUID, removeMembers map[OVNPortGroup][]OVNSwitchPortUUID) error { +func (o *NB) PortGroupMemberChange(addMembers map[OVNPortGroup][]OVNSwitchPortUUID, removeMembers map[OVNPortGroup][]OVNSwitchPortUUID) error { args := []string{} for portGroupName, portMemberUUIDs := range addMembers { @@ -1661,7 +1653,7 @@ func (o *OVN) PortGroupMemberChange(addMembers map[OVNPortGroup][]OVNSwitchPortU } // PortGroupSetACLRules applies a set of rules to the specified port group. Any existing rules are removed. -func (o *OVN) PortGroupSetACLRules(portGroupName OVNPortGroup, matchReplace map[string]string, aclRules ...OVNACLRule) error { +func (o *NB) PortGroupSetACLRules(portGroupName OVNPortGroup, matchReplace map[string]string, aclRules ...OVNACLRule) error { // Remove any existing rules assigned to the entity. args := []string{"clear", "port_group", string(portGroupName), "acls"} @@ -1682,7 +1674,7 @@ func (o *OVN) PortGroupSetACLRules(portGroupName OVNPortGroup, matchReplace map[ // aclRuleAddAppendArgs adds the commands to args that add the provided ACL rules to the specified OVN entity. // Returns args with the ACL rule add commands added to it. -func (o *OVN) aclRuleAddAppendArgs(args []string, entityTable string, entityName string, externalIDs map[string]string, matchReplace map[string]string, aclRules ...OVNACLRule) []string { +func (o *NB) aclRuleAddAppendArgs(args []string, entityTable string, entityName string, externalIDs map[string]string, matchReplace map[string]string, aclRules ...OVNACLRule) []string { for i, rule := range aclRules { if len(args) > 0 { args = append(args, "--") @@ -1722,7 +1714,7 @@ func (o *OVN) aclRuleAddAppendArgs(args []string, entityTable string, entityName // aclRuleDeleteAppendArgs adds the commands to args that delete the provided ACL rules from the specified OVN entity. // Returns args with the ACL rule delete commands added to it. -func (o *OVN) aclRuleDeleteAppendArgs(args []string, entityTable string, entityName string, aclRuleUUIDs []string) []string { +func (o *NB) aclRuleDeleteAppendArgs(args []string, entityTable string, entityName string, aclRuleUUIDs []string) []string { for _, aclRuleUUID := range aclRuleUUIDs { if len(args) > 0 { args = append(args, "--") @@ -1736,7 +1728,7 @@ func (o *OVN) aclRuleDeleteAppendArgs(args []string, entityTable string, entityN // PortGroupPortSetACLRules applies a set of rules for the logical switch port in the specified port group. // Any existing rules for that logical switch port in the port group are removed. -func (o *OVN) PortGroupPortSetACLRules(portGroupName OVNPortGroup, portName OVNSwitchPort, aclRules ...OVNACLRule) error { +func (o *NB) PortGroupPortSetACLRules(portGroupName OVNPortGroup, portName OVNSwitchPort, aclRules ...OVNACLRule) error { // Remove any existing rules assigned to the entity. removeACLRuleUUIDs, err := o.logicalSwitchPortACLRules(portName) if err != nil { @@ -1762,7 +1754,7 @@ func (o *OVN) PortGroupPortSetACLRules(portGroupName OVNPortGroup, portName OVNS } // PortGroupPortClearACLRules clears any rules assigned to the logical switch port in the specified port group. -func (o *OVN) PortGroupPortClearACLRules(portGroupName OVNPortGroup, portName OVNSwitchPort) error { +func (o *NB) PortGroupPortClearACLRules(portGroupName OVNPortGroup, portName OVNSwitchPort) error { // Remove any existing rules assigned to the entity. removeACLRuleUUIDs, err := o.logicalSwitchPortACLRules(portName) if err != nil { @@ -1783,7 +1775,7 @@ func (o *OVN) PortGroupPortClearACLRules(portGroupName OVNPortGroup, portName OV // LoadBalancerApply creates a new load balancer (if doesn't exist) on the specified routers and switches. // Providing an empty set of vips will delete the load balancer. -func (o *OVN) LoadBalancerApply(loadBalancerName OVNLoadBalancer, routers []OVNRouter, switches []OVNSwitch, vips ...OVNLoadBalancerVIP) error { +func (o *NB) LoadBalancerApply(loadBalancerName OVNLoadBalancer, routers []OVNRouter, switches []OVNSwitch, vips ...OVNLoadBalancerVIP) error { lbTCPName := fmt.Sprintf("%s-tcp", loadBalancerName) lbUDPName := fmt.Sprintf("%s-udp", loadBalancerName) @@ -1884,7 +1876,7 @@ func (o *OVN) LoadBalancerApply(loadBalancerName OVNLoadBalancer, routers []OVNR } // LoadBalancerDelete deletes the specified load balancer(s). -func (o *OVN) LoadBalancerDelete(loadBalancerNames ...OVNLoadBalancer) error { +func (o *NB) LoadBalancerDelete(loadBalancerNames ...OVNLoadBalancer) error { var args []string for _, loadBalancerName := range loadBalancerNames { @@ -1911,7 +1903,7 @@ func (o *OVN) LoadBalancerDelete(loadBalancerNames ...OVNLoadBalancer) error { // AddressSetCreate creates address sets for IP versions 4 and 6 in the format "_ip". // Populates them with the relevant addresses supplied. -func (o *OVN) AddressSetCreate(addressSetPrefix OVNAddressSet, addresses ...net.IPNet) error { +func (o *NB) AddressSetCreate(addressSetPrefix OVNAddressSet, addresses ...net.IPNet) error { args := []string{ "create", "address_set", fmt.Sprintf("name=%s_ip%d", addressSetPrefix, 4), "--", "create", "address_set", fmt.Sprintf("name=%s_ip%d", addressSetPrefix, 6), @@ -1942,7 +1934,7 @@ func (o *OVN) AddressSetCreate(addressSetPrefix OVNAddressSet, addresses ...net. // AddressSetAdd adds the supplied addresses to the address sets, or creates a new address sets if needed. // The address set name used is "_ip", e.g. "foo_ip4". -func (o *OVN) AddressSetAdd(addressSetPrefix OVNAddressSet, addresses ...net.IPNet) error { +func (o *NB) AddressSetAdd(addressSetPrefix OVNAddressSet, addresses ...net.IPNet) error { var args []string ipVersions := make(map[uint]struct{}) @@ -1986,7 +1978,7 @@ func (o *OVN) AddressSetAdd(addressSetPrefix OVNAddressSet, addresses ...net.IPN // AddressSetRemove removes the supplied addresses from the address set. // The address set name used is "_ip", e.g. "foo_ip4". -func (o *OVN) AddressSetRemove(addressSetPrefix OVNAddressSet, addresses ...net.IPNet) error { +func (o *NB) AddressSetRemove(addressSetPrefix OVNAddressSet, addresses ...net.IPNet) error { var args []string for _, address := range addresses { @@ -2013,7 +2005,7 @@ func (o *OVN) AddressSetRemove(addressSetPrefix OVNAddressSet, addresses ...net. } // AddressSetDelete deletes address sets for IP versions 4 and 6 in the format "_ip". -func (o *OVN) AddressSetDelete(addressSetPrefix OVNAddressSet) error { +func (o *NB) AddressSetDelete(addressSetPrefix OVNAddressSet) error { _, err := o.nbctl( "--if-exists", "destroy", "address_set", fmt.Sprintf("%s_ip%d", addressSetPrefix, 4), "--", "--if-exists", "destroy", "address_set", fmt.Sprintf("%s_ip%d", addressSetPrefix, 6), @@ -2026,7 +2018,7 @@ func (o *OVN) AddressSetDelete(addressSetPrefix OVNAddressSet) error { } // LogicalRouterPolicyApply removes any existing policies and applies the new policies to the specified router. -func (o *OVN) LogicalRouterPolicyApply(routerName OVNRouter, policies ...OVNRouterPolicy) error { +func (o *NB) LogicalRouterPolicyApply(routerName OVNRouter, policies ...OVNRouterPolicy) error { args := []string{"lr-policy-del", string(routerName)} for _, policy := range policies { @@ -2042,7 +2034,7 @@ func (o *OVN) LogicalRouterPolicyApply(routerName OVNRouter, policies ...OVNRout } // LogicalRouterRoutes returns a list of static routes in the main route table of the logical router. -func (o *OVN) LogicalRouterRoutes(routerName OVNRouter) ([]OVNRouterRoute, error) { +func (o *NB) LogicalRouterRoutes(routerName OVNRouter) ([]OVNRouterRoute, error) { output, err := o.nbctl("lr-route-list", string(routerName)) if err != nil { return nil, err @@ -2114,7 +2106,7 @@ func (o *OVN) LogicalRouterRoutes(routerName OVNRouter) ([]OVNRouterRoute, error } // LogicalRouterPeeringApply applies a peering relationship between two logical routers. -func (o *OVN) LogicalRouterPeeringApply(opts OVNRouterPeering) error { +func (o *NB) LogicalRouterPeeringApply(opts OVNRouterPeering) error { if len(opts.LocalRouterPortIPs) <= 0 || len(opts.TargetRouterPortIPs) <= 0 { return fmt.Errorf("IPs not populated for both router ports") } @@ -2210,7 +2202,7 @@ func (o *OVN) LogicalRouterPeeringApply(opts OVNRouterPeering) error { // LogicalRouterPeeringDelete deletes a peering relationship between two logical routers. // Requires LocalRouter, LocalRouterPort, TargetRouter and TargetRouterPort opts fields to be populated. -func (o *OVN) LogicalRouterPeeringDelete(opts OVNRouterPeering) error { +func (o *NB) LogicalRouterPeeringDelete(opts OVNRouterPeering) error { // Remove peering router ports and static routes using ports from both routers. if opts.LocalRouter == "" || opts.TargetRouter == "" { return fmt.Errorf("Router names not populated for both routers") @@ -2255,7 +2247,7 @@ func (o *OVN) LogicalRouterPeeringDelete(opts OVNRouterPeering) error { } // GetHardwareAddress gets the hardware address of the logical router port. -func (o *OVN) GetHardwareAddress(ovnRouterPort OVNRouterPort) (string, error) { +func (o *NB) GetHardwareAddress(ovnRouterPort OVNRouterPort) (string, error) { nameFilter := fmt.Sprintf("name=%s", ovnRouterPort) hwaddr, err := o.nbctl("--no-headings", "--data=bare", "--format=csv", "--columns=mac", "find", "Logical_Router_Port", nameFilter) if err != nil { From dca81f07bf12fceedd6cf3358d73e6abf12d4d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Tue, 19 Dec 2023 18:30:24 -0500 Subject: [PATCH 31/38] incusd: Update for OVN NB struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- internal/server/device/nic_ovn.go | 6 +-- internal/server/network/acl/acl_ovn.go | 10 ++--- internal/server/network/acl/driver_common.go | 2 +- internal/server/network/driver_ovn.go | 46 ++++++++++---------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/internal/server/device/nic_ovn.go b/internal/server/device/nic_ovn.go index 75a31d8b294..58f9ef2036f 100644 --- a/internal/server/device/nic_ovn.go +++ b/internal/server/device/nic_ovn.go @@ -615,7 +615,7 @@ func (d *nicOVN) Start() (*deviceConfig.RunConfig, error) { return nil, fmt.Errorf("Failed getting OVS Chassis ID: %w", err) } - ovnClient, err := ovn.NewOVN(d.state) + ovnClient, err := ovn.NewNB(d.state) if err != nil { return nil, fmt.Errorf("Failed to get OVN client: %w", err) } @@ -758,7 +758,7 @@ func (d *nicOVN) Update(oldDevices deviceConfig.Devices, isRunning bool) error { } if len(removedACLs) > 0 { - client, err := ovn.NewOVN(d.state) + client, err := ovn.NewNB(d.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -962,7 +962,7 @@ func (d *nicOVN) Remove() error { // Check for port groups that will become unused (and need deleting) as this NIC is deleted. securityACLs := util.SplitNTrimSpace(d.config["security.acls"], ",", -1, true) if len(securityACLs) > 0 { - client, err := ovn.NewOVN(d.state) + client, err := ovn.NewNB(d.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } diff --git a/internal/server/network/acl/acl_ovn.go b/internal/server/network/acl/acl_ovn.go index 50204e8c47c..721b9fed5a7 100644 --- a/internal/server/network/acl/acl_ovn.go +++ b/internal/server/network/acl/acl_ovn.go @@ -81,7 +81,7 @@ func OVNIntSwitchRouterPortName(networkID int64) ovn.OVNSwitchPort { // of the database and applied. For each network provided in aclNets, the network specific port group for each ACL // is checked for existence (it is created & applies network specific ACL rules if not). // Returns a revert fail function that can be used to undo this function if a subsequent step fails. -func OVNEnsureACLs(s *state.State, l logger.Logger, client *ovn.OVN, aclProjectName string, aclNameIDs map[string]int64, aclNets map[string]NetworkACLUsage, aclNames []string, reapplyRules bool) (revert.Hook, error) { +func OVNEnsureACLs(s *state.State, l logger.Logger, client *ovn.NB, aclProjectName string, aclNameIDs map[string]int64, aclNets map[string]NetworkACLUsage, aclNames []string, reapplyRules bool) (revert.Hook, error) { revert := revert.New() defer revert.Fail() @@ -323,7 +323,7 @@ func ovnAddReferencedACLs(info *api.NetworkACL, referencedACLNames map[string]st } // ovnApplyToPortGroup applies the rules in the specified ACL to the specified port group. -func ovnApplyToPortGroup(l logger.Logger, client *ovn.OVN, aclInfo *api.NetworkACL, portGroupName ovn.OVNPortGroup, aclNameIDs map[string]int64, aclNets map[string]NetworkACLUsage, peerTargetNetIDs map[db.NetworkPeer]int64) error { +func ovnApplyToPortGroup(l logger.Logger, client *ovn.NB, aclInfo *api.NetworkACL, portGroupName ovn.OVNPortGroup, aclNameIDs map[string]int64, aclNets map[string]NetworkACLUsage, peerTargetNetIDs map[db.NetworkPeer]int64) error { // Create slice for port group rules that has the capacity for ingress and egress rules, plus default rule. portGroupRules := make([]ovn.OVNACLRule, 0, len(aclInfo.Ingress)+len(aclInfo.Egress)+1) networkRules := make([]ovn.OVNACLRule, 0) @@ -626,7 +626,7 @@ func ovnRuleSubjectToOVNACLMatch(direction string, aclNameIDs map[string]int64, } // OVNApplyNetworkBaselineRules applies preset baseline logical switch rules to a allow access to network services. -func OVNApplyNetworkBaselineRules(client *ovn.OVN, switchName ovn.OVNSwitch, routerPortName ovn.OVNSwitchPort, intRouterIPs []*net.IPNet, dnsIPs []net.IP) error { +func OVNApplyNetworkBaselineRules(client *ovn.NB, switchName ovn.OVNSwitch, routerPortName ovn.OVNSwitchPort, intRouterIPs []*net.IPNet, dnsIPs []net.IP) error { rules := []ovn.OVNACLRule{ { Direction: "to-lport", @@ -746,7 +746,7 @@ func OVNApplyNetworkBaselineRules(client *ovn.OVN, switchName ovn.OVNSwitch, rou // The combination of ignoring the specifified usage type and explicit keep ACLs allows the caller to ensure that // the desired ACLs are considered unused by the usage type even if the referring config has not yet been removed // from the database. -func OVNPortGroupDeleteIfUnused(s *state.State, l logger.Logger, client *ovn.OVN, aclProjectName string, ignoreUsageType any, ignoreUsageNicName string, keepACLs ...string) error { +func OVNPortGroupDeleteIfUnused(s *state.State, l logger.Logger, client *ovn.NB, aclProjectName string, ignoreUsageType any, ignoreUsageNicName string, keepACLs ...string) error { // Get map of ACL names to DB IDs (used for generating OVN port group names). aclNameIDs, err := s.DB.Cluster.GetNetworkACLIDsByNames(aclProjectName) if err != nil { @@ -973,7 +973,7 @@ func OVNPortGroupInstanceNICSchedule(portUUID ovn.OVNSwitchPortUUID, changeSet m } // OVNApplyInstanceNICDefaultRules applies instance NIC default rules to per-network port group. -func OVNApplyInstanceNICDefaultRules(client *ovn.OVN, switchPortGroup ovn.OVNPortGroup, logPrefix string, nicPortName ovn.OVNSwitchPort, ingressAction string, ingressLogged bool, egressAction string, egressLogged bool) error { +func OVNApplyInstanceNICDefaultRules(client *ovn.NB, switchPortGroup ovn.OVNPortGroup, logPrefix string, nicPortName ovn.OVNSwitchPort, ingressAction string, ingressLogged bool, egressAction string, egressLogged bool) error { if !util.ValueInSlice(ingressAction, ValidActions) { return fmt.Errorf("Invalid ingress action %q", ingressAction) } diff --git a/internal/server/network/acl/driver_common.go b/internal/server/network/acl/driver_common.go index de4e85e6c91..96ccd82d141 100644 --- a/internal/server/network/acl/driver_common.go +++ b/internal/server/network/acl/driver_common.go @@ -631,7 +631,7 @@ func (d *common) Update(config *api.NetworkACLPut, clientType request.ClientType // If there are affected OVN networks, then apply the changes, but only if the request type is normal. // This way we won't apply the same changes multiple times for each cluster member. if len(aclOVNNets) > 0 && clientType == request.ClientTypeNormal { - ovnnb, err := ovn.NewOVN(d.state) + ovnnb, err := ovn.NewNB(d.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } diff --git a/internal/server/network/driver_ovn.go b/internal/server/network/driver_ovn.go index 2dab373585c..072279115bd 100644 --- a/internal/server/network/driver_ovn.go +++ b/internal/server/network/driver_ovn.go @@ -130,7 +130,7 @@ func (n *ovn) State() (*api.NetworkState, error) { }) } - ovnnb, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewNB(n.state) if err != nil { return nil, err } @@ -1843,7 +1843,7 @@ func (n *ovn) setup(update bool) error { revert := revert.New() defer revert.Fail() - ovnnb, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewNB(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -2423,7 +2423,7 @@ func (n *ovn) setup(update bool) error { // Optionally excludePeers takes a list of peer network IDs to exclude from the router policy. This is useful // when removing a peer connection as it allows the security policy to be removed from OVN for that peer before the // peer connection has been removed from the database. -func (n *ovn) logicalRouterPolicySetup(ovnnb *networkOVN.OVN, excludePeers ...int64) error { +func (n *ovn) logicalRouterPolicySetup(ovnnb *networkOVN.NB, excludePeers ...int64) error { extRouterPort := n.getRouterExtPortName() intRouterPort := n.getRouterIntPortName() addrSetPrefix := acl.OVNIntSwitchPortGroupAddressSetPrefix(n.ID()) @@ -2486,7 +2486,7 @@ func (n *ovn) logicalRouterPolicySetup(ovnnb *networkOVN.OVN, excludePeers ...in // ensureNetworkPortGroup ensures that the network level port group (used for classifying NICs connected to this // network as internal) exists. func (n *ovn) ensureNetworkPortGroup(projectID int64) error { - ovnnb, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewNB(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -2514,7 +2514,7 @@ func (n *ovn) ensureNetworkPortGroup(projectID int64) error { // The chassis priority value is a stable-random value derived from chassis group name and node ID. This is so we // don't end up using the same chassis for the primary uplink chassis for all OVN networks in a cluster. func (n *ovn) addChassisGroupEntry() error { - ovnnb, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewNB(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -2579,7 +2579,7 @@ func (n *ovn) addChassisGroupEntry() error { // deleteChassisGroupEntry deletes an entry for the local OVS chassis from the OVN logical network's chassis group. func (n *ovn) deleteChassisGroupEntry() error { - ovnnb, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewNB(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -2609,7 +2609,7 @@ func (n *ovn) Delete(clientType request.ClientType) error { } if clientType == request.ClientTypeNormal { - ovnnb, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewNB(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -2983,7 +2983,7 @@ func (n *ovn) Update(newNetwork api.NetworkPut, targetNode string, clientType re addChangeSet := map[networkOVN.OVNPortGroup][]networkOVN.OVNSwitchPortUUID{} removeChangeSet := map[networkOVN.OVNPortGroup][]networkOVN.OVNSwitchPortUUID{} - ovnnb, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewNB(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -3325,7 +3325,7 @@ func (n *ovn) InstanceDevicePortAdd(instanceUUID string, deviceName string, devi revert := revert.New() defer revert.Fail() - ovnnb, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewNB(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -3406,7 +3406,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL revert := revert.New() defer revert.Fail() - ovnnb, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewNB(n.state) if err != nil { return "", nil, fmt.Errorf("Failed to get OVN client: %w", err) } @@ -3940,7 +3940,7 @@ func (n *ovn) InstanceDevicePortIPs(instanceUUID string, deviceName string) ([]n return nil, fmt.Errorf("Instance UUID is required") } - ovnnb, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewNB(n.state) if err != nil { return nil, fmt.Errorf("Failed to get OVN client: %w", err) } @@ -3969,7 +3969,7 @@ func (n *ovn) InstanceDevicePortStop(ovsExternalOVNPort networkOVN.OVNSwitchPort source = "internal" } - ovnnb, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewNB(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -4094,7 +4094,7 @@ func (n *ovn) InstanceDevicePortRemove(instanceUUID string, deviceName string, d revert := revert.New() defer revert.Fail() - ovnnb, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewNB(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -4347,7 +4347,7 @@ func (n *ovn) handleDependencyChange(uplinkName string, uplinkConfig map[string] if util.ValueInSlice("ovn.ingress_mode", changedKeys) { n.logger.Debug("Applying ingress mode changes from uplink network to instance NICs", logger.Ctx{"uplink": uplinkName}) - ovnnb, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewNB(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -4557,7 +4557,7 @@ func (n *ovn) ForwardCreate(forward api.NetworkForwardsPost, clientType request. } } - ovnnb, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewNB(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -4641,7 +4641,7 @@ func (n *ovn) ForwardUpdate(listenAddress string, req api.NetworkForwardPut, cli return nil // Nothing has changed. } - ovnnb, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewNB(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -4704,7 +4704,7 @@ func (n *ovn) ForwardDelete(listenAddress string, clientType request.ClientType) return err } - ovnnb, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewNB(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -4868,7 +4868,7 @@ func (n *ovn) LoadBalancerCreate(loadBalancer api.NetworkLoadBalancersPost, clie } } - ovnnb, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewNB(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -4952,7 +4952,7 @@ func (n *ovn) LoadBalancerUpdate(listenAddress string, req api.NetworkLoadBalanc return nil // Nothing has changed. } - ovnnb, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewNB(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -5016,7 +5016,7 @@ func (n *ovn) LoadBalancerDelete(listenAddress string, clientType request.Client return err } - ovnnb, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewNB(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -5182,7 +5182,7 @@ func (n *ovn) PeerCreate(peer api.NetworkPeersPost) error { return fmt.Errorf("Only peerings in %q state can be setup", api.NetworkStatusCreated) } - ovnnb, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewNB(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } @@ -5297,7 +5297,7 @@ func (n *ovn) peerGetLocalOpts(localNICRoutes []net.IPNet) (*networkOVN.OVNRoute // peerSetup applies the network peering configuration to both networks. // Accepts an OVN client, a target OVN network, and a set of OVNRouterPeering options pre-filled with local config. -func (n *ovn) peerSetup(ovnnb *networkOVN.OVN, targetOVNNet *ovn, opts networkOVN.OVNRouterPeering) error { +func (n *ovn) peerSetup(ovnnb *networkOVN.NB, targetOVNNet *ovn, opts networkOVN.OVNRouterPeering) error { targetRouterMAC, err := targetOVNNet.getRouterMAC() if err != nil { return fmt.Errorf("Failed getting target router MAC address: %w", err) @@ -5457,7 +5457,7 @@ func (n *ovn) PeerDelete(peerName string) error { TargetRouterPort: targetOVNNet.getLogicalRouterPeerPortName(n.ID()), } - ovnnb, err := networkOVN.NewOVN(n.state) + ovnnb, err := networkOVN.NewNB(n.state) if err != nil { return fmt.Errorf("Failed to get OVN client: %w", err) } From 30ffa557d8bd36f94813598dc8f6d4816b3bd7c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Tue, 19 Dec 2023 19:35:34 -0500 Subject: [PATCH 32/38] incusd/network/ovn: Port PortGroupInfo to OVSDB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- internal/server/network/ovn/ovn_nb_actions.go | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/internal/server/network/ovn/ovn_nb_actions.go b/internal/server/network/ovn/ovn_nb_actions.go index c871647fba5..7ef76fe7233 100644 --- a/internal/server/network/ovn/ovn_nb_actions.go +++ b/internal/server/network/ovn/ovn_nb_actions.go @@ -9,6 +9,7 @@ import ( "time" "github.com/ovn-org/libovsdb/ovsdb" + ovsClient "github.com/ovn-org/libovsdb/client" "github.com/lxc/incus/internal/iprange" ovnNB "github.com/lxc/incus/internal/server/network/ovn/schema/ovn-nb" @@ -1533,23 +1534,22 @@ func (o *NB) ChassisGroupChassisDelete(haChassisGroupName OVNChassisGroup, chass // PortGroupInfo returns the port group UUID or empty string if port doesn't exist, and whether the port group has // any ACL rules defined on it. func (o *NB) PortGroupInfo(portGroupName OVNPortGroup) (OVNPortGroupUUID, bool, error) { - groupInfo, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid,name,acl", "find", "port_group", - fmt.Sprintf("name=%s", string(portGroupName)), - ) - if err != nil { - return "", false, err - } + ctx := context.TODO() - groupParts := util.SplitNTrimSpace(groupInfo, ",", 3, true) - if len(groupParts) == 3 { - if groupParts[1] == string(portGroupName) { - aclParts := util.SplitNTrimSpace(groupParts[2], ",", -1, true) + pg := &ovnNB.PortGroup{ + Name: string(portGroupName), + } - return OVNPortGroupUUID(groupParts[0]), len(aclParts) > 0, nil + err := o.client.Get(ctx, pg) + if err != nil { + if err == ovsClient.ErrNotFound { + return "", false, nil } + + return "", false, err } - return "", false, nil + return OVNPortGroupUUID(pg.UUID), len(pg.ACLs) > 0, nil } // PortGroupAdd creates a new port group and optionally adds logical switch ports to the group. From 46400e8926e201f3df7d645638150b5c41d0d4a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Tue, 19 Dec 2023 20:08:49 -0500 Subject: [PATCH 33/38] incusd/network/ovn: Port LogicalSwitchPortDynamicIPs to OVSDB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- internal/server/network/ovn/ovn_nb_actions.go | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/internal/server/network/ovn/ovn_nb_actions.go b/internal/server/network/ovn/ovn_nb_actions.go index 7ef76fe7233..524ab5080f3 100644 --- a/internal/server/network/ovn/ovn_nb_actions.go +++ b/internal/server/network/ovn/ovn_nb_actions.go @@ -1134,24 +1134,23 @@ func (o *NB) LogicalSwitchPortIPs(portName OVNSwitchPort) ([]net.IP, error) { // LogicalSwitchPortDynamicIPs returns a list of dynamc IPs for a switch port. func (o *NB) LogicalSwitchPortDynamicIPs(portName OVNSwitchPort) ([]net.IP, error) { - dynamicAddressesRaw, err := o.nbctl("get", "logical_switch_port", string(portName), "dynamic_addresses") - if err != nil { - return nil, err + ctx := context.TODO() + + lsp := &ovnNB.LogicalSwitchPort{ + Name: string(portName), } - dynamicAddressesRaw = strings.TrimSpace(dynamicAddressesRaw) + err := o.client.Get(ctx, lsp) + if err != nil { + return []net.IP{}, err + } // Check if no dynamic IPs set. - if dynamicAddressesRaw == "[]" { + if lsp.DynamicAddresses == nil { return []net.IP{}, nil } - dynamicAddressesRaw, err = unquote(dynamicAddressesRaw) - if err != nil { - return nil, fmt.Errorf("Failed unquoting: %w", err) - } - - dynamicAddresses := strings.Split(strings.TrimSpace(dynamicAddressesRaw), " ") + dynamicAddresses := strings.Split(*lsp.DynamicAddresses, " ") dynamicIPs := make([]net.IP, 0, len(dynamicAddresses)) for _, dynamicAddress := range dynamicAddresses { From b2633938159721b0bb8a767c640beb2be57795cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Wed, 20 Dec 2023 15:17:39 -0500 Subject: [PATCH 34/38] incusd/network/ovs: Add OVSDB client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- internal/server/network/ovs/ovs.go | 76 ++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 3 deletions(-) diff --git a/internal/server/network/ovs/ovs.go b/internal/server/network/ovs/ovs.go index c11c4bdc1e8..f2401097042 100644 --- a/internal/server/network/ovs/ovs.go +++ b/internal/server/network/ovs/ovs.go @@ -1,9 +1,79 @@ package ovs +import ( + "context" + "fmt" + "runtime" + + "github.com/go-logr/logr" + ovsdbClient "github.com/ovn-org/libovsdb/client" + + ovsSwitch "github.com/lxc/incus/internal/server/network/ovs/schema/ovs" +) + // VSwitch client. -type VSwitch struct{} +type VSwitch struct { + client ovsdbClient.Client + cookie ovsdbClient.MonitorCookie + rootUUID string +} // NewVSwitch initialises a new vSwitch client.. -func NewVSwitch() *VSwitch { - return &VSwitch{} +func NewVSwitch() (*VSwitch, error) { + // Prepare the OVSDB client. + dbSchema, err := ovsSwitch.FullDatabaseModel() + if err != nil { + return nil, err + } + + discard := logr.Discard() + + options := []ovsdbClient.Option{ + ovsdbClient.WithLogger(&discard), + ovsdbClient.WithEndpoint("unix:///run/openvswitch/db.sock"), + } + + // Connect to OVSDB. + ovs, err := ovsdbClient.NewOVSDBClient(dbSchema, options...) + if err != nil { + return nil, err + } + + err = ovs.Connect(context.TODO()) + if err != nil { + return nil, err + } + + err = ovs.Echo(context.TODO()) + if err != nil { + return nil, err + } + + monitorCookie, err := ovs.MonitorAll(context.TODO()) + if err != nil { + return nil, err + } + + // Create the SB struct. + client := &VSwitch{ + client: ovs, + cookie: monitorCookie, + } + + // Set finalizer to stop the monitor. + runtime.SetFinalizer(client, func(o *VSwitch) { + _ = ovs.MonitorCancel(context.Background(), o.cookie) + }) + + // Get the root UUID. + rows := ovs.Cache().Table("Open_vSwitch").Rows() + if len(rows) != 1 { + return nil, fmt.Errorf("Cannot find the OVS root switch") + } + + for uuid := range rows { + client.rootUUID = uuid + } + + return client, nil } From 4e38102dbc6f80f46e0713a84143fac9550a375f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Wed, 20 Dec 2023 15:17:54 -0500 Subject: [PATCH 35/38] incusd: Update for NewVSwitch changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- cmd/incusd/networks.go | 6 +- internal/server/device/nic_bridged.go | 5 +- internal/server/device/nic_ovn.go | 32 ++++++++-- internal/server/network/driver_bridge.go | 14 +++-- internal/server/network/driver_ovn.go | 60 +++++++++++++++---- .../server/network/network_utils_bridge.go | 16 +++-- .../server/network/network_utils_sriov.go | 5 +- internal/server/network/ovn/ovn_nb_actions.go | 2 +- internal/server/network/ovn/ovn_sb.go | 7 ++- 9 files changed, 117 insertions(+), 30 deletions(-) diff --git a/cmd/incusd/networks.go b/cmd/incusd/networks.go index cab51dfde35..811262235e9 100644 --- a/cmd/incusd/networks.go +++ b/cmd/incusd/networks.go @@ -865,7 +865,11 @@ func doNetworkGet(s *state.State, r *http.Request, allNodes bool, projectName st } else if util.PathExists(fmt.Sprintf("/sys/class/net/%s/bonding", apiNet.Name)) { apiNet.Type = "bond" } else { - vswitch := ovs.NewVSwitch() + vswitch, err := ovs.NewVSwitch() + if err != nil { + return api.Network{}, fmt.Errorf("Failed to connect to OVS: %w", err) + } + exists, _ := vswitch.BridgeExists(apiNet.Name) if exists { apiNet.Type = "bridge" diff --git a/internal/server/device/nic_bridged.go b/internal/server/device/nic_bridged.go index fae0e3f1dbd..51079848691 100644 --- a/internal/server/device/nic_bridged.go +++ b/internal/server/device/nic_bridged.go @@ -1529,7 +1529,10 @@ func (d *nicBridged) setupNativeBridgePortVLANs(hostName string) error { // setupOVSBridgePortVLANs configures the bridge port with the specified VLAN settings on the openvswitch bridge. func (d *nicBridged) setupOVSBridgePortVLANs(hostName string) error { - vswitch := ovs.NewVSwitch() + vswitch, err := ovs.NewVSwitch() + if err != nil { + return fmt.Errorf("Failed to connect to OVS: %w", err) + } // Set port on bridge to specified untagged PVID. if d.config["vlan"] != "" { diff --git a/internal/server/device/nic_ovn.go b/internal/server/device/nic_ovn.go index 58f9ef2036f..b1fe7593fc0 100644 --- a/internal/server/device/nic_ovn.go +++ b/internal/server/device/nic_ovn.go @@ -409,7 +409,11 @@ func (d *nicOVN) Start() (*deviceConfig.RunConfig, error) { delete(saveData, "host_name") // Nested NICs don't have a host side interface. } else { if d.config["acceleration"] == "sriov" { - vswitch := ovs.NewVSwitch() + vswitch, err := ovs.NewVSwitch() + if err != nil { + return nil, fmt.Errorf("Failed to connect to OVS: %w", err) + } + if !vswitch.HardwareOffloadingEnabled() { return nil, fmt.Errorf("SR-IOV acceleration requires hardware offloading be enabled in OVS") } @@ -456,12 +460,16 @@ func (d *nicOVN) Start() (*deviceConfig.RunConfig, error) { integrationBridgeNICName = vfRepresentor peerName = vfDev } else if d.config["acceleration"] == "vdpa" { - vswitch := ovs.NewVSwitch() + vswitch, err := ovs.NewVSwitch() + if err != nil { + return nil, fmt.Errorf("Failed to connect to OVS: %w", err) + } + if !vswitch.HardwareOffloadingEnabled() { return nil, fmt.Errorf("SR-IOV acceleration requires hardware offloading be enabled in OVS") } - err := linux.LoadModule("vdpa") + err = linux.LoadModule("vdpa") if err != nil { return nil, fmt.Errorf("Error loading %q module: %w", "vdpa", err) } @@ -609,7 +617,11 @@ func (d *nicOVN) Start() (*deviceConfig.RunConfig, error) { runConf := deviceConfig.RunConfig{} // Get local chassis ID for chassis group. - vswitch := ovs.NewVSwitch() + vswitch, err := ovs.NewVSwitch() + if err != nil { + return nil, fmt.Errorf("Failed to connect to OVS: %w", err) + } + chassisID, err := vswitch.ChassisID() if err != nil { return nil, fmt.Errorf("Failed getting OVS Chassis ID: %w", err) @@ -825,7 +837,11 @@ func (d *nicOVN) Stop() (*deviceConfig.RunConfig, error) { // port name using the same regime it does for new ports. This part is only here in order to allow // instance ports generated under an older regime to be cleaned up properly. networkVethFillFromVolatile(d.config, v) - vswitch := ovs.NewVSwitch() + vswitch, err := ovs.NewVSwitch() + if err != nil { + d.logger.Error("Failed to connect to OVS", logger.Ctx{"err": err}) + } + var ovsExternalOVNPort string if d.config["nested"] == "" { ovsExternalOVNPort, err = vswitch.InterfaceAssociatedOVNSwitchPort(d.config["host_name"]) @@ -1127,7 +1143,11 @@ func (d *nicOVN) setupHostNIC(hostName string, ovnPortName ovn.OVNSwitchPort, up // Attach host side veth interface to bridge. integrationBridge := d.state.GlobalConfig.NetworkOVNIntegrationBridge() - vswitch := ovs.NewVSwitch() + vswitch, err := ovs.NewVSwitch() + if err != nil { + return nil, fmt.Errorf("Failed to connect to OVS: %w", err) + } + err = vswitch.BridgePortAdd(integrationBridge, hostName, true) if err != nil { return nil, err diff --git a/internal/server/network/driver_bridge.go b/internal/server/network/driver_bridge.go index 48ad854c43e..1292ca3677b 100644 --- a/internal/server/network/driver_bridge.go +++ b/internal/server/network/driver_bridge.go @@ -581,14 +581,14 @@ func (n *bridge) setup(oldConfig map[string]string) error { // Create the bridge interface if doesn't exist. if !n.isRunning() { if n.config["bridge.driver"] == "openvswitch" { - vswitch := ovs.NewVSwitch() - if !vswitch.Installed() { + vswitch, err := ovs.NewVSwitch() + if err != nil || !vswitch.Installed() { return fmt.Errorf("Open vSwitch isn't installed on this system") } // Add and configure the interface in one operation to reduce the number of executions and // to avoid systemd-udevd from applying the default MACAddressPolicy=persistent policy. - err := vswitch.BridgeAdd(n.name, false, bridge.Address, bridge.MTU) + err = vswitch.BridgeAdd(n.name, false, bridge.Address, bridge.MTU) if err != nil { return err } @@ -1440,8 +1440,12 @@ func (n *bridge) Stop() error { // Destroy the bridge interface if n.config["bridge.driver"] == "openvswitch" { - vswitch := ovs.NewVSwitch() - err := vswitch.BridgeDelete(n.name) + vswitch, err := ovs.NewVSwitch() + if err != nil { + return err + } + + err = vswitch.BridgeDelete(n.name) if err != nil { return err } diff --git a/internal/server/network/driver_ovn.go b/internal/server/network/driver_ovn.go index 072279115bd..c54b9ac0ed5 100644 --- a/internal/server/network/driver_ovn.go +++ b/internal/server/network/driver_ovn.go @@ -659,7 +659,11 @@ func (n *ovn) getUnderlayInfo() (uint32, net.IP, error) { return 0, fmt.Errorf("No matching interface found for OVN enscapsulation IP %q", findIP.String()) } - vswitch := ovs.NewVSwitch() + vswitch, err := ovs.NewVSwitch() + if err != nil { + return 0, nil, fmt.Errorf("Failed to connect to OVS: %w", err) + } + encapIP, err := vswitch.OVNEncapIP() if err != nil { return 0, nil, fmt.Errorf("Failed getting OVN enscapsulation IP from OVS: %w", err) @@ -1283,7 +1287,11 @@ func (n *ovn) startUplinkPortBridgeNative(uplinkNet Network, bridgeDevice string } // Create uplink OVS bridge if needed. - vswitch := ovs.NewVSwitch() + vswitch, err := ovs.NewVSwitch() + if err != nil { + return fmt.Errorf("Failed to connect to OVS: %w", err) + } + err = vswitch.BridgeAdd(vars.ovsBridge, true, nil, 0) if err != nil { return fmt.Errorf("Failed to create uplink OVS bridge %q: %w", vars.ovsBridge, err) @@ -1315,8 +1323,12 @@ func (n *ovn) startUplinkPortBridgeOVS(uplinkNet Network, bridgeDevice string) e defer revert.Fail() // If uplink is an openvswitch bridge, have OVN logical provider connect directly to it. - vswitch := ovs.NewVSwitch() - err := vswitch.OVNBridgeMappingAdd(bridgeDevice, uplinkNet.Name()) + vswitch, err := ovs.NewVSwitch() + if err != nil { + return fmt.Errorf("Failed to connect to OVS: %w", err) + } + + err = vswitch.OVNBridgeMappingAdd(bridgeDevice, uplinkNet.Name()) if err != nil { return fmt.Errorf("Failed to associate uplink OVS bridge %q to OVN provider %q: %w", bridgeDevice, uplinkNet.Name(), err) } @@ -1391,7 +1403,11 @@ func (n *ovn) startUplinkPortPhysical(uplinkNet Network) error { } // Detect if uplink interface is a OVS bridge. - vswitch := ovs.NewVSwitch() + vswitch, err := ovs.NewVSwitch() + if err != nil { + return fmt.Errorf("Failed to connect to OVS: %w", err) + } + isOVSBridge, _ := vswitch.BridgeExists(uplinkHostName) if isOVSBridge { return n.startUplinkPortBridgeOVS(uplinkNet, uplinkHostName) @@ -1535,7 +1551,15 @@ func (n *ovn) deleteUplinkPortBridgeNative(uplinkNet Network) error { if !uplinkUsed { removeVeths = true - vswitch := ovs.NewVSwitch() + vswitch, err := ovs.NewVSwitch() + if err != nil { + return fmt.Errorf("Failed to connect to OVS: %w", err) + } + + if err != nil { + return fmt.Errorf("Failed to connect to OVS: %w", err) + } + err = vswitch.OVNBridgeMappingDelete(vars.ovsBridge, uplinkNet.Name()) if err != nil { return err @@ -1581,7 +1605,11 @@ func (n *ovn) deleteUplinkPortBridgeOVS(uplinkNet Network, ovsBridge string) err // Remove uplink OVS bridge mapping if not in use by other OVN networks. if !uplinkUsed { - vswitch := ovs.NewVSwitch() + vswitch, err := ovs.NewVSwitch() + if err != nil { + return fmt.Errorf("Failed to connect to OVS: %w", err) + } + err = vswitch.OVNBridgeMappingDelete(ovsBridge, uplinkNet.Name()) if err != nil { return err @@ -1602,7 +1630,11 @@ func (n *ovn) deleteUplinkPortPhysical(uplinkNet Network) error { } // Detect if uplink interface is a OVS bridge. - vswitch := ovs.NewVSwitch() + vswitch, err := ovs.NewVSwitch() + if err != nil { + return fmt.Errorf("Failed to connect to OVS: %w", err) + } + isOVSBridge, _ := vswitch.BridgeExists(uplinkHostName) if isOVSBridge { return n.deleteUplinkPortBridgeOVS(uplinkNet, uplinkHostName) @@ -2520,7 +2552,11 @@ func (n *ovn) addChassisGroupEntry() error { } // Get local chassis ID for chassis group. - vswitch := ovs.NewVSwitch() + vswitch, err := ovs.NewVSwitch() + if err != nil { + return fmt.Errorf("Failed to connect to OVS: %w", err) + } + chassisID, err := vswitch.ChassisID() if err != nil { return fmt.Errorf("Failed getting OVS Chassis ID: %w", err) @@ -2585,7 +2621,11 @@ func (n *ovn) deleteChassisGroupEntry() error { } // Remove local chassis from chassis group. - vswitch := ovs.NewVSwitch() + vswitch, err := ovs.NewVSwitch() + if err != nil { + return fmt.Errorf("Failed to connect to OVS: %w", err) + } + chassisID, err := vswitch.ChassisID() if err != nil { return fmt.Errorf("Failed getting OVS Chassis ID: %w", err) diff --git a/internal/server/network/network_utils_bridge.go b/internal/server/network/network_utils_bridge.go index fccdfc77531..01a165b090a 100644 --- a/internal/server/network/network_utils_bridge.go +++ b/internal/server/network/network_utils_bridge.go @@ -64,8 +64,12 @@ func AttachInterface(bridgeName string, devName string) error { return err } } else { - vswitch := ovs.NewVSwitch() - err := vswitch.BridgePortAdd(bridgeName, devName, true) + vswitch, err := ovs.NewVSwitch() + if err != nil { + return fmt.Errorf("Failed to connect to OVS: %w", err) + } + + err = vswitch.BridgePortAdd(bridgeName, devName, true) if err != nil { return err } @@ -83,8 +87,12 @@ func DetachInterface(bridgeName string, devName string) error { return err } } else { - vswitch := ovs.NewVSwitch() - err := vswitch.BridgePortDelete(bridgeName, devName) + vswitch, err := ovs.NewVSwitch() + if err != nil { + return fmt.Errorf("Failed to connect to OVS: %w", err) + } + + err = vswitch.BridgePortDelete(bridgeName, devName) if err != nil { return err } diff --git a/internal/server/network/network_utils_sriov.go b/internal/server/network/network_utils_sriov.go index f482ca8b519..1fed19e2850 100644 --- a/internal/server/network/network_utils_sriov.go +++ b/internal/server/network/network_utils_sriov.go @@ -375,7 +375,10 @@ func SRIOVFindFreeVFAndRepresentor(state *state.State, ovsBridgeName string) (st return "", "", "", -1, fmt.Errorf("Failed to read directory %q: %w", sysClassNet, err) } - vswitch := ovs.NewVSwitch() + vswitch, err := ovs.NewVSwitch() + if err != nil { + return "", "", "", -1, fmt.Errorf("Failed to connect to OVS: %w", err) + } // Get all ports on the integration bridge. ports, err := vswitch.BridgePortList(ovsBridgeName) diff --git a/internal/server/network/ovn/ovn_nb_actions.go b/internal/server/network/ovn/ovn_nb_actions.go index 524ab5080f3..2b14c10d8d9 100644 --- a/internal/server/network/ovn/ovn_nb_actions.go +++ b/internal/server/network/ovn/ovn_nb_actions.go @@ -8,8 +8,8 @@ import ( "strings" "time" - "github.com/ovn-org/libovsdb/ovsdb" ovsClient "github.com/ovn-org/libovsdb/client" + "github.com/ovn-org/libovsdb/ovsdb" "github.com/lxc/incus/internal/iprange" ovnNB "github.com/lxc/incus/internal/server/network/ovn/schema/ovn-nb" diff --git a/internal/server/network/ovn/ovn_sb.go b/internal/server/network/ovn/ovn_sb.go index 8bebda86507..9f19225f029 100644 --- a/internal/server/network/ovn/ovn_sb.go +++ b/internal/server/network/ovn/ovn_sb.go @@ -27,7 +27,12 @@ type SB struct { // NewSB initialises new OVN client for Southbound operations. func NewSB(s *state.State) (*SB, error) { // Get the database connection string. - dbAddr, err := ovs.NewVSwitch().OVNSouthboundDBRemoteAddress() + vswitch, err := ovs.NewVSwitch() + if err != nil { + return nil, fmt.Errorf("Failed to connect to OVS: %w", err) + } + + dbAddr, err := vswitch.OVNSouthboundDBRemoteAddress() if err != nil { return nil, fmt.Errorf("Failed to get OVN southbound connection string: %w", err) } From 4657e645fdbcfd1e5d7eb0c742f97d1522d27c67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Wed, 20 Dec 2023 15:29:07 -0500 Subject: [PATCH 36/38] incusd/network/ovs: Port BridgeExists to OVSDB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- internal/server/network/ovs/ovs_actions.go | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/internal/server/network/ovs/ovs_actions.go b/internal/server/network/ovs/ovs_actions.go index 521382a8f8d..f5f3d0fedb8 100644 --- a/internal/server/network/ovs/ovs_actions.go +++ b/internal/server/network/ovs/ovs_actions.go @@ -1,13 +1,17 @@ package ovs import ( + "context" "fmt" "net" "os/exec" "strings" "sync" + ovsdbClient "github.com/ovn-org/libovsdb/client" + "github.com/lxc/incus/internal/server/ip" + ovsSwitch "github.com/lxc/incus/internal/server/network/ovs/schema/ovs" "github.com/lxc/incus/shared/subprocess" ) @@ -22,16 +26,13 @@ func (o *VSwitch) Installed() bool { // BridgeExists returns true if the bridge exists. func (o *VSwitch) BridgeExists(bridgeName string) (bool, error) { - _, err := subprocess.RunCommand("ovs-vsctl", "br-exists", bridgeName) - if err != nil { - runErr, ok := err.(subprocess.RunError) - if ok { - exitError, ok := runErr.Unwrap().(*exec.ExitError) + ctx := context.TODO() + bridge := &ovsSwitch.Bridge{Name: bridgeName} - // ovs-vsctl manpage says that br-exists exits with code 2 if bridge doesn't exist. - if ok && exitError.ExitCode() == 2 { - return false, nil - } + err := o.client.Get(ctx, bridge) + if err != nil { + if err == ovsdbClient.ErrNotFound { + return false, nil } return false, err From 200d947c91767ae1d98daf0ba77c010430e44814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Wed, 20 Dec 2023 15:32:50 -0500 Subject: [PATCH 37/38] incusd/network/ovs: Port ChassisID to OVSDB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- internal/server/network/ovs/ovs_actions.go | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/internal/server/network/ovs/ovs_actions.go b/internal/server/network/ovs/ovs_actions.go index f5f3d0fedb8..8eddabc1de0 100644 --- a/internal/server/network/ovs/ovs_actions.go +++ b/internal/server/network/ovs/ovs_actions.go @@ -160,22 +160,19 @@ func (o *VSwitch) InterfaceAssociatedOVNSwitchPort(interfaceName string) (string // ChassisID returns the local chassis ID. func (o *VSwitch) ChassisID() (string, error) { - // ovs-vsctl's get command doesn't support its --format flag, so we always get the output quoted. - // However ovs-vsctl's find and list commands don't support retrieving a single column's map field. - // And ovs-vsctl's JSON output is unfriendly towards statically typed languages as it mixes data types - // in a slice. So stick with "get" command and use Go's strconv.Unquote to return the actual values. - chassisID, err := subprocess.RunCommand("ovs-vsctl", "get", "open_vswitch", ".", "external_ids:system-id") - if err != nil { - return "", err + ctx := context.TODO() + + vSwitch := &ovsSwitch.OpenvSwitch{ + UUID: o.rootUUID, } - chassisID = strings.TrimSpace(chassisID) - chassisID, err = unquote(chassisID) + err := o.client.Get(ctx, vSwitch) if err != nil { - return "", fmt.Errorf("Failed unquoting: %w", err) + return "", err } - return chassisID, nil + val := vSwitch.ExternalIDs["system-id"] + return val, nil } // OVNEncapIP returns the enscapsulation IP used for OVN underlay tunnels. From 72c2cf3dab79439f2ba89d8d1576b1486d93743a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Wed, 20 Dec 2023 15:35:45 -0500 Subject: [PATCH 38/38] incusd/network/ovs: Port OVNBridgeMappings to OVSDB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber Sponsored-by: Luizalabs (https://luizalabs.com) --- internal/server/network/ovs/ovs_actions.go | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/internal/server/network/ovs/ovs_actions.go b/internal/server/network/ovs/ovs_actions.go index 8eddabc1de0..45a87b08e51 100644 --- a/internal/server/network/ovs/ovs_actions.go +++ b/internal/server/network/ovs/ovs_actions.go @@ -202,26 +202,19 @@ func (o *VSwitch) OVNEncapIP() (net.IP, error) { // OVNBridgeMappings gets the current OVN bridge mappings. func (o *VSwitch) OVNBridgeMappings(bridgeName string) ([]string, error) { - // ovs-vsctl's get command doesn't support its --format flag, so we always get the output quoted. - // However ovs-vsctl's find and list commands don't support retrieving a single column's map field. - // And ovs-vsctl's JSON output is unfriendly towards statically typed languages as it mixes data types - // in a slice. So stick with "get" command and use Go's strconv.Unquote to return the actual values. - mappings, err := subprocess.RunCommand("ovs-vsctl", "--if-exists", "get", "open_vswitch", ".", "external-ids:ovn-bridge-mappings") - if err != nil { - return nil, err - } + ctx := context.TODO() - mappings = strings.TrimSpace(mappings) - if mappings == "" { - return []string{}, nil + vSwitch := &ovsSwitch.OpenvSwitch{ + UUID: o.rootUUID, } - mappings, err = unquote(mappings) + err := o.client.Get(ctx, vSwitch) if err != nil { - return nil, fmt.Errorf("Failed unquoting: %w", err) + return nil, err } - return strings.SplitN(mappings, ",", -1), nil + val := vSwitch.ExternalIDs["ovn-bridge-mappings"] + return strings.SplitN(val, ",", -1), nil } // OVNBridgeMappingAdd appends an OVN bridge mapping between a bridge and the logical provider name.