go.ligato.io/vpp-agent/v3@v3.5.0/examples/customize/custom_api_model/main.go (about) 1 // Copyright (c) 2017 Cisco and/or its affiliates. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at: 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package main 16 17 import ( 18 "context" 19 "fmt" 20 "log" 21 "net" 22 "os" 23 "time" 24 25 "github.com/namsral/flag" 26 "go.ligato.io/cn-infra/v2/agent" 27 "go.ligato.io/cn-infra/v2/infra" 28 "go.ligato.io/cn-infra/v2/logging" 29 "google.golang.org/grpc" 30 "google.golang.org/protobuf/encoding/prototext" 31 32 "go.ligato.io/vpp-agent/v3/client" 33 "go.ligato.io/vpp-agent/v3/client/remoteclient" 34 "go.ligato.io/vpp-agent/v3/cmd/vpp-agent/app" 35 "go.ligato.io/vpp-agent/v3/examples/customize/custom_api_model/proto/custom" 36 "go.ligato.io/vpp-agent/v3/plugins/orchestrator" 37 "go.ligato.io/vpp-agent/v3/proto/ligato/linux" 38 linux_interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/linux/interfaces" 39 linux_l3 "go.ligato.io/vpp-agent/v3/proto/ligato/linux/l3" 40 "go.ligato.io/vpp-agent/v3/proto/ligato/vpp" 41 interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/interfaces" 42 vpp_l2 "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/l2" 43 ) 44 45 //go:generate protoc --proto_path=. --go_out=paths=source_relative:. proto/custom/model.proto 46 47 var ( 48 clientType = flag.String("client", "local", "Client type used in demonstration [local, remote]") 49 ) 50 51 func init() { 52 log.SetFlags(log.Lshortfile | log.Lmicroseconds) 53 } 54 55 func main() { 56 example := NewExample() 57 58 a := agent.NewAgent( 59 agent.AllPlugins(example), 60 ) 61 62 if err := a.Start(); err != nil { 63 log.Fatal(err) 64 } 65 66 var c client.ConfigClient 67 68 switch *clientType { 69 case "local": 70 // Local client - using direct in-process calls. 71 c = client.LocalClient 72 logging.Info("Using Local Client - in-process calls") 73 74 case "remote": 75 // Remote client - using gRPC connection to the agent. 76 conn, err := grpc.Dial("unix", 77 grpc.WithInsecure(), 78 grpc.WithDialer(dialer("tcp", "127.0.0.1:9111", time.Second*3)), 79 ) 80 if err != nil { 81 log.Fatal(err) 82 } 83 defer conn.Close() 84 85 c, err = remoteclient.NewClientGRPC(conn) 86 if err != nil { 87 log.Fatal(err) 88 } 89 logging.Info("Using Remote Client - gRPC API") 90 91 default: 92 log.Printf("unknown client type: %q", *clientType) 93 flag.Usage() 94 os.Exit(1) 95 } 96 97 demonstrateClient(c) 98 99 if err := a.Stop(); err != nil { 100 log.Fatal(err) 101 } 102 } 103 104 // Example demonstrates the use of the remoteclient to locally transport example configuration into the default VPP plugins. 105 type Example struct { 106 infra.PluginDeps 107 app.VPP 108 app.Linux 109 Orchestrator *orchestrator.Plugin 110 } 111 112 func NewExample() *Example { 113 ep := &Example{ 114 VPP: app.DefaultVPP(), 115 Linux: app.DefaultLinux(), 116 Orchestrator: &orchestrator.DefaultPlugin, 117 } 118 ep.SetName("custom-api-model-example") 119 ep.SetupLog() 120 return ep 121 } 122 123 // Init initializes example plugin. 124 func (p *Example) Init() (err error) { 125 p.Log.Info("Initialization complete") 126 return nil 127 } 128 129 func demonstrateClient(c client.ConfigClient) { 130 // List known models 131 fmt.Println("# ==========================================") 132 fmt.Println("# List known models..") 133 fmt.Println("# ==========================================") 134 knownModels, err := c.KnownModels("config") 135 if err != nil { 136 log.Println("KnownModels failed:", err) 137 } 138 fmt.Printf("listing %d models\n", len(knownModels)) 139 for _, model := range knownModels { 140 fmt.Printf(" - %v\n", model.String()) 141 } 142 time.Sleep(time.Second * 1) 143 144 // Resync config 145 fmt.Println("# ==========================================") 146 fmt.Println("# Requesting config resync..") 147 fmt.Println("# ==========================================") 148 customModel := &custom.MyModel{ 149 Name: "TheModel", 150 } 151 err = c.ResyncConfig( 152 memif1, memif2, 153 veth1, veth2, 154 routeX, routeCache, 155 customModel, 156 ) 157 if err != nil { 158 log.Println("ResyncConfig failed:", err) 159 } 160 time.Sleep(time.Second * 2) 161 162 // Change config 163 fmt.Println("# ==========================================") 164 fmt.Println("# Requesting config change..") 165 fmt.Println("# ==========================================") 166 memif1.Enabled = false 167 memif1.Mtu = 666 168 mymodel := &custom.MyModel{ 169 Name: "my1", 170 Value: 33, 171 } 172 173 req := c.ChangeRequest() 174 req.Update(afp1, memif1, bd1, vppRoute1, mymodel) 175 req.Delete(memif2) 176 if err := req.Send(context.Background()); err != nil { 177 log.Fatalln(err) 178 } 179 time.Sleep(time.Second * 2) 180 181 // Get config 182 fmt.Println("# ==========================================") 183 fmt.Println("# Retrieving config..") 184 fmt.Println("# ==========================================") 185 type config struct { 186 VPP vpp.ConfigData 187 Linux linux.ConfigData 188 MyModels []*custom.MyModel 189 } 190 var cfg config 191 if err := c.GetConfig(&cfg.VPP, &cfg.Linux, &cfg); err != nil { 192 log.Println("GetConfig failed:", err) 193 } 194 fmt.Printf("Retrieved config:\n%+v\n", &cfg) 195 196 // Dump state 197 fmt.Println("# ==========================================") 198 fmt.Println("# Dumping state..") 199 fmt.Println("# ==========================================") 200 states, err := c.DumpState() 201 if err != nil { 202 log.Println("DumpState failed:", err) 203 } 204 fmt.Printf("Dumping %d states\n", len(states)) 205 for _, state := range states { 206 fmt.Printf(" - %v\n", prototext.Format(state)) 207 } 208 } 209 210 // Dialer for unix domain socket 211 func dialer(socket, address string, timeoutVal time.Duration) func(string, time.Duration) (net.Conn, error) { 212 return func(addr string, timeout time.Duration) (net.Conn, error) { 213 // Pass values 214 addr, timeout = address, timeoutVal 215 // Dial with timeout 216 return net.DialTimeout(socket, addr, timeoutVal) 217 } 218 } 219 220 var ( 221 memif1 = &vpp.Interface{ 222 Name: "memif1", 223 Enabled: true, 224 IpAddresses: []string{"3.3.0.1/16"}, 225 Type: interfaces.Interface_MEMIF, 226 Link: &interfaces.Interface_Memif{ 227 Memif: &interfaces.MemifLink{ 228 Id: 1, 229 Master: true, 230 Secret: "secret", 231 SocketFilename: "/tmp/memif1.sock", 232 }, 233 }, 234 } 235 memif2 = &vpp.Interface{ 236 Name: "memif1.1", 237 Enabled: true, 238 Type: interfaces.Interface_SUB_INTERFACE, 239 IpAddresses: []string{"3.10.0.1/24"}, 240 Link: &interfaces.Interface_Sub{ 241 Sub: &interfaces.SubInterface{ 242 ParentName: "memif1", 243 SubId: 10, 244 }, 245 }, 246 } 247 bd1 = &vpp.BridgeDomain{ 248 Name: "bd1", 249 Interfaces: []*vpp_l2.BridgeDomain_Interface{ 250 {Name: "memif1"}, 251 }, 252 } 253 vppRoute1 = &vpp.Route{ 254 OutgoingInterface: "memif1", 255 DstNetwork: "4.4.10.0/24", 256 NextHopAddr: "3.10.0.5", 257 } 258 afp1 = &vpp.Interface{ 259 Name: "afp1", 260 Enabled: true, 261 Type: interfaces.Interface_AF_PACKET, 262 IpAddresses: []string{"10.10.3.5/24"}, 263 Link: &interfaces.Interface_Afpacket{ 264 Afpacket: &interfaces.AfpacketLink{ 265 HostIfName: "veth1", 266 }, 267 }, 268 } 269 veth1 = &linux.Interface{ 270 Name: "myVETH1", 271 Type: linux_interfaces.Interface_VETH, 272 Enabled: true, 273 HostIfName: "veth1", 274 IpAddresses: []string{"10.10.3.1/24"}, 275 Link: &linux_interfaces.Interface_Veth{ 276 Veth: &linux_interfaces.VethLink{ 277 PeerIfName: "myVETH2", 278 }, 279 }, 280 } 281 veth2 = &linux.Interface{ 282 Name: "myVETH2", 283 Type: linux_interfaces.Interface_VETH, 284 Enabled: true, 285 HostIfName: "veth2", 286 Link: &linux_interfaces.Interface_Veth{ 287 Veth: &linux_interfaces.VethLink{ 288 PeerIfName: "myVETH1", 289 }, 290 }, 291 } 292 routeX = &linux.Route{ 293 DstNetwork: "192.168.5.0/24", 294 OutgoingInterface: "myVETH1", 295 GwAddr: "10.10.3.254", 296 Scope: linux_l3.Route_GLOBAL, 297 } 298 routeCache = &linux.Route{ 299 DstNetwork: "10.10.5.0/24", 300 OutgoingInterface: "if10", 301 GwAddr: "10.10.5.254", 302 Scope: linux_l3.Route_GLOBAL, 303 } 304 )