blob: 65d883a9e61130be1eda58f9b382dd2665b92adc [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 (
sslobodr392ebd52019-01-18 12:41:49 -050021 "errors"
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040022 "fmt"
sslobodr392ebd52019-01-18 12:41:49 -050023 "github.com/opencord/voltha-go/common/log"
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040024 "google.golang.org/grpc"
sslobodr392ebd52019-01-18 12:41:49 -050025)
26
27type RoundRobinRouter struct {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040028 name string
29 routerType int // TODO: Likely not needed.
sslobodr392ebd52019-01-18 12:41:49 -050030 grpcService string
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040031 bkndClstr *backendCluster
32 curBknd **backend
sslobodr392ebd52019-01-18 12:41:49 -050033}
34
sslobodrcd37bc52019-01-24 11:47:16 -050035func newRoundRobinRouter(rconf *RouterConfig, config *RouteConfig) (Router, error) {
sslobodr392ebd52019-01-18 12:41:49 -050036 var err error = nil
37 var rtrn_err bool = false
38 // Validate the configuration
39
40 log.Debug("Creating a new round robin router")
41 // A name must exist
42 if config.Name == "" {
43 log.Error("A router 'name' must be specified")
44 rtrn_err = true
45 }
46
47 if rconf.ProtoPackage == "" {
48 log.Error("A 'package' must be specified")
49 rtrn_err = true
50 }
51
52 if rconf.ProtoService == "" {
53 log.Error("A 'service' must be specified")
54 rtrn_err = true
55 }
56
57 var bptr *backend
58 bptr = nil
59 rr := RoundRobinRouter{
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040060 name: config.Name,
61 grpcService: rconf.ProtoService,
62 curBknd: &bptr,
sslobodr392ebd52019-01-18 12:41:49 -050063 }
64
65 // This has already been validated bfore this function
66 // is called so just use it.
sslobodr5f0b5a32019-01-24 07:45:19 -050067 for idx := range rTypeNames {
sslobodr392ebd52019-01-18 12:41:49 -050068 if config.Type == rTypeNames[idx] {
69 rr.routerType = idx
70 break
71 }
72 }
73
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040074 // Create the backend cluster or link to an existing one
sslobodr392ebd52019-01-18 12:41:49 -050075 ok := true
76 if rr.bkndClstr, ok = bClusters[config.backendCluster.Name]; ok == false {
sslobodrcd37bc52019-01-24 11:47:16 -050077 if rr.bkndClstr, err = newBackendCluster(config.backendCluster); err != nil {
sslobodr392ebd52019-01-18 12:41:49 -050078 log.Errorf("Could not create a backend for router %s", config.Name)
79 rtrn_err = true
80 }
81 }
82
83 if rtrn_err {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040084 return rr, errors.New(fmt.Sprintf("Failed to create a new router '%s'", rr.name))
sslobodr392ebd52019-01-18 12:41:49 -050085 }
86
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040087 return rr, nil
sslobodr392ebd52019-01-18 12:41:49 -050088}
89
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040090func (rr RoundRobinRouter) GetMetaKeyVal(serverStream grpc.ServerStream) (string, string, error) {
91 return "", "", nil
sslobodr392ebd52019-01-18 12:41:49 -050092}
93
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040094func (rr RoundRobinRouter) BackendCluster(s string, mk string) (*backendCluster, error) {
sslobodr392ebd52019-01-18 12:41:49 -050095 return rr.bkndClstr, nil
96}
97
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040098func (rr RoundRobinRouter) Name() string {
sslobodr392ebd52019-01-18 12:41:49 -050099 return rr.name
100}
101
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400102func (rr RoundRobinRouter) Route(sel interface{}) *backend {
sslobodr392ebd52019-01-18 12:41:49 -0500103 var err error
104 switch sl := sel.(type) {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400105 case *nbFrame:
106 // Since this is a round robin router just get the next backend
107 if *rr.curBknd, err = rr.bkndClstr.nextBackend(*rr.curBknd, BE_SEQ_RR); err == nil {
108 return *rr.curBknd
109 } else {
110 sl.err = err
sslobodr392ebd52019-01-18 12:41:49 -0500111 return nil
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400112 }
113 default:
114 log.Errorf("Internal: invalid data type in Route call %v", sel)
115 return nil
sslobodr392ebd52019-01-18 12:41:49 -0500116 }
sslobodr392ebd52019-01-18 12:41:49 -0500117}
118
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400119func (rr RoundRobinRouter) Service() string {
sslobodr392ebd52019-01-18 12:41:49 -0500120 return rr.grpcService
121}
122
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400123func (rr RoundRobinRouter) FindBackendCluster(becName string) *backendCluster {
124 if becName == rr.bkndClstr.name {
sslobodr360c8d72019-02-05 12:47:56 -0500125 return rr.bkndClstr
126 }
127 return nil
sslobodr392ebd52019-01-18 12:41:49 -0500128}
129
130func (rr RoundRobinRouter) ReplyHandler(sel interface{}) error { // This is a no-op
131 return nil
132}