blob: aec122190907aefd3797a3eaa5c5d08ca8a76f26 [file] [log] [blame]
sslobodr392ebd52019-01-18 12:41:49 -05001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16// gRPC affinity router with active/active backends
17
18package afrouter
19
20import (
21 "net"
22 "fmt"
sslobodr392ebd52019-01-18 12:41:49 -050023 "errors"
sslobodr1d1e50b2019-03-14 09:17:40 -040024 "runtime"
25 "strconv"
sslobodr392ebd52019-01-18 12:41:49 -050026 "google.golang.org/grpc"
27 "golang.org/x/net/context"
28 "github.com/opencord/voltha-go/common/log"
William Kurkiandaa6bb22019-03-07 12:26:28 -050029 pb "github.com/opencord/voltha-protos/go/afrouter"
sslobodr392ebd52019-01-18 12:41:49 -050030)
31
32
33type ArouterApi struct {
34 addr string
35 port int
36 apiListener net.Listener
37 apiServer * grpc.Server
38 running bool
39 ar *ArouterProxy
40}
41
sslobodrcd37bc52019-01-24 11:47:16 -050042func newApi(config *ApiConfig, ar *ArouterProxy) (*ArouterApi, error) {
sslobodr392ebd52019-01-18 12:41:49 -050043 var rtrn_err bool
44 // Create a seperate server and listener for the API
45 // Validate the ip address if one is provided
46 if ip := net.ParseIP(config.Addr); config.Addr != "" && ip == nil {
47 log.Errorf("Invalid address '%s' provided for API server", config.Addr)
48 rtrn_err = true
49 }
50 if rtrn_err == true {
51 return nil, errors.New("Errors in API configuration")
52 } else {
53 var err error = nil
54 aa := &ArouterApi{addr:config.Addr,port:int(config.Port),ar:ar}
55 // Create the listener for the API server
56 if aa.apiListener, err =
57 net.Listen("tcp", config.Addr + ":"+
58 strconv.Itoa(int(config.Port))); err != nil {
59 log.Error(err)
60 return nil, err
61 }
62 // Create the API server
63 aa.apiServer = grpc.NewServer()
64 pb.RegisterConfigurationServer(aa.apiServer, *aa)
65 return aa,err
66 }
67}
68
69func (aa *ArouterApi) getServer(srvr string) (*server, error) {
70 if s,ok := aa.ar.servers[srvr]; ok == false {
71 err := errors.New(fmt.Sprintf("Server '%s' doesn't exist", srvr))
72 return nil, err
73 } else {
74 return s, nil
75 }
76}
77
78func (aa *ArouterApi) getRouter(s *server, clstr string) (Router, error) {
79 for _,pkg := range s.routers {
80 for _,r := range pkg {
81 if c := r.FindBackendCluster(clstr); c != nil {
82 return r, nil
83 }
84 }
85 }
86 err := errors.New(fmt.Sprintf("Cluster '%s' doesn't exist", clstr))
87 return nil, err
88}
89
90func (aa *ArouterApi) getCluster(s *server, clstr string) (*backendCluster, error) {
91 for _,pkg := range s.routers {
92 for _,r := range pkg {
93 if c := r.FindBackendCluster(clstr); c != nil {
94 return c, nil
95 }
96 }
97 }
98 err := errors.New(fmt.Sprintf("Cluster '%s' doesn't exist", clstr))
99 return nil, err
100}
101
102func (aa *ArouterApi) getBackend(c *backendCluster, bknd string) (*backend, error) {
103 for _,b := range c.backends {
104 if b.name == bknd {
105 return b,nil
106 }
107 }
sslobodr360c8d72019-02-05 12:47:56 -0500108 err := errors.New(fmt.Sprintf("Backend '%s' doesn't exist in cluster %s",
109 bknd, c.name))
sslobodr392ebd52019-01-18 12:41:49 -0500110 return nil, err
111}
112
113func (aa *ArouterApi) getConnection(b *backend, con string) (*beConnection, error) {
114 if c,ok := b.connections[con]; ok == false {
115 err := errors.New(fmt.Sprintf("Connection '%s' doesn't exist", con))
116 return nil, err
117 } else {
118 return c, nil
119 }
120}
121
122func (aa * ArouterApi) updateConnection(in *pb.Conn, cn *beConnection, b *backend) error {
123 sPort := strconv.FormatUint(in.Port,10)
124 // Check that the ip address and or port are different
125 if in.Addr == cn.addr && sPort == cn.port {
126 err := errors.New(fmt.Sprintf("Refusing to change connection '%s' to identical values", in.Connection))
127 return err
128 }
129 //log.Debugf("BEFORE: Be1: %v Be2 %v", cn.bknd, b)
130 cn.close()
131 cn.addr = in.Addr
132 cn.port = sPort
133 cn.connect()
134 return nil
135}
136
137func (aa ArouterApi) SetAffinity(ctx context.Context, in *pb.Affinity) (*pb.Result, error) {
138 log.Debugf("SetAffinity called! %v",in);
139 //return &pb.Result{Success:true,Error:""},nil
140 // Navigate down tot he connection and compare IP addresses and ports if they're
141 // not the same then close the existing connection. If they are bothe the same
142 // then return an error describing the situation.
143 var err error
144
145 aap := &aa
146
147 _=aap
148
149 log.Debugf("Getting router %s and route %s", in.Router, in.Route)
150 if r,ok := allRouters[in.Router+in.Route]; ok == true {
151 switch rr := r.(type) {
152 case AffinityRouter:
153 log.Debug("Affinity router found")
154 b := rr.FindBackendCluster(in.Cluster).getBackend(in.Backend)
155 if b != nil {
156 rr.setAffinity(in.Id, b)
157 } else {
158 log.Errorf("Requested backend '%s' not found", in.Backend)
159 }
160 _ = rr
161 case MethodRouter:
162 log.Debug("Method router found")
163 _ = rr
164 default:
165 log.Debug("Some other router found")
166 _ = rr
167 }
168 } else {
169 log.Debugf("Couldn't get router type")
170 return &pb.Result{Success:false,Error:err.Error()}, err
171 }
172
173 return &pb.Result{Success:true,Error:""},nil
174}
175
176func (aa ArouterApi) SetConnection(ctx context.Context, in *pb.Conn) (*pb.Result, error) {
sslobodr392ebd52019-01-18 12:41:49 -0500177 // Navigate down tot he connection and compare IP addresses and ports if they're
178 // not the same then close the existing connection. If they are bothe the same
179 // then return an error describing the situation.
180 var s *server
181 var c *backendCluster
182 var b * backend
183 var cn * beConnection
184 var err error
185
sslobodr360c8d72019-02-05 12:47:56 -0500186 log.Debugf("SetConnection called! %v",in);
187
sslobodr392ebd52019-01-18 12:41:49 -0500188 aap := &aa
189 if s,err = (aap).getServer(in.Server); err != nil {
190 err := errors.New(fmt.Sprintf("Server '%s' doesn't exist", in.Server))
sslobodr360c8d72019-02-05 12:47:56 -0500191 log.Error(err)
sslobodr392ebd52019-01-18 12:41:49 -0500192 return &pb.Result{Success:false,Error:err.Error()}, err
193 }
194 // The cluster is usually accessed via tha router but since each
195 // cluster is unique it's good enough to find the router that
196 // has the cluster we're looking for rather than fully keying
197 // the path
198 if c,err = aap.getCluster(s, in.Cluster); err != nil {
sslobodr360c8d72019-02-05 12:47:56 -0500199 log.Error(err)
sslobodr392ebd52019-01-18 12:41:49 -0500200 return &pb.Result{Success:false,Error:err.Error()}, err
201 }
202
203 if b,err = aap.getBackend(c, in.Backend); err != nil {
sslobodr360c8d72019-02-05 12:47:56 -0500204 log.Error(err)
sslobodr392ebd52019-01-18 12:41:49 -0500205 return &pb.Result{Success:false,Error:err.Error()}, err
206 }
207
208 if cn,err = aap.getConnection(b, in.Connection); err != nil {
sslobodr360c8d72019-02-05 12:47:56 -0500209 log.Error(err)
sslobodr392ebd52019-01-18 12:41:49 -0500210 return &pb.Result{Success:false,Error:err.Error()}, err
211 }
212
213 if err = aap.updateConnection(in, cn, b); err != nil {
sslobodr360c8d72019-02-05 12:47:56 -0500214 log.Error(err)
sslobodr392ebd52019-01-18 12:41:49 -0500215 return &pb.Result{Success:false,Error:err.Error()}, err
216 }
217
218 return &pb.Result{Success:true,Error:""},nil
219}
220
sslobodr1d1e50b2019-03-14 09:17:40 -0400221func (aa ArouterApi) GetGoroutineCount(ctx context.Context, in *pb.Empty) (*pb.Count, error) {
222 return &pb.Count{Count:uint32(runtime.NumGoroutine())}, nil
223}
224
sslobodr392ebd52019-01-18 12:41:49 -0500225func (aa *ArouterApi) serve() {
226 // Start a serving thread
227 go func() {
228 aa.running = true
229 if err := aa.apiServer.Serve(aa.apiListener); err != nil {
230 aa.running = false
231 log.Error(err)
232 errChan <- err
233 }
234 }()
235}
236