blob: f0ebd0ef7634129486b6707c68e7c10849c68427 [file] [log] [blame]
David K. Bainbridge157bdab2020-01-16 14:38:05 -08001/*
2 Copyright 2020 the original author or authors.
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
17package ofagent
18
19import (
20 "context"
David Bainbridgef8ce7d22020-04-08 12:49:41 -070021 "sync"
22 "time"
23
24 "github.com/opencord/ofagent-go/internal/pkg/holder"
David K. Bainbridge157bdab2020-01-16 14:38:05 -080025 "github.com/opencord/ofagent-go/internal/pkg/openflow"
David K. Bainbridgeaea73cd2020-01-27 10:44:50 -080026 "github.com/opencord/voltha-lib-go/v3/pkg/log"
27 "github.com/opencord/voltha-lib-go/v3/pkg/probe"
28 "github.com/opencord/voltha-protos/v3/go/voltha"
David K. Bainbridge157bdab2020-01-16 14:38:05 -080029 "google.golang.org/grpc"
David K. Bainbridge157bdab2020-01-16 14:38:05 -080030)
31
David K. Bainbridge157bdab2020-01-16 14:38:05 -080032type ofaEvent byte
33type ofaState byte
34
35const (
36 ofaEventStart = ofaEvent(iota)
37 ofaEventVolthaConnected
38 ofaEventVolthaDisconnected
39 ofaEventError
40
41 ofaStateConnected = ofaState(iota)
David K. Bainbridge9cb404e2020-01-28 14:32:29 -080042 ofaStateConnecting
David K. Bainbridge157bdab2020-01-16 14:38:05 -080043 ofaStateDisconnected
44)
45
46type OFAgent struct {
47 VolthaApiEndPoint string
Jonathan Hart4b110f62020-03-13 17:36:19 -070048 OFControllerEndPoints []string
David K. Bainbridge157bdab2020-01-16 14:38:05 -080049 DeviceListRefreshInterval time.Duration
50 ConnectionMaxRetries int
51 ConnectionRetryDelay time.Duration
52
53 volthaConnection *grpc.ClientConn
David Bainbridgef8ce7d22020-04-08 12:49:41 -070054 volthaClient *holder.VolthaServiceClientHolder
David K. Bainbridge157bdab2020-01-16 14:38:05 -080055 mapLock sync.Mutex
56 clientMap map[string]*openflow.OFClient
57 events chan ofaEvent
58
59 packetInChannel chan *voltha.PacketIn
60 packetOutChannel chan *voltha.PacketOut
61 changeEventChannel chan *voltha.ChangeEvent
62}
63
64func NewOFAgent(config *OFAgent) (*OFAgent, error) {
65 ofa := OFAgent{
66 VolthaApiEndPoint: config.VolthaApiEndPoint,
Jonathan Hart4b110f62020-03-13 17:36:19 -070067 OFControllerEndPoints: config.OFControllerEndPoints,
David K. Bainbridge157bdab2020-01-16 14:38:05 -080068 DeviceListRefreshInterval: config.DeviceListRefreshInterval,
69 ConnectionMaxRetries: config.ConnectionMaxRetries,
70 ConnectionRetryDelay: config.ConnectionRetryDelay,
David Bainbridgef8ce7d22020-04-08 12:49:41 -070071 volthaClient: &holder.VolthaServiceClientHolder{},
David K. Bainbridge157bdab2020-01-16 14:38:05 -080072 packetInChannel: make(chan *voltha.PacketIn),
73 packetOutChannel: make(chan *voltha.PacketOut),
74 changeEventChannel: make(chan *voltha.ChangeEvent),
75 clientMap: make(map[string]*openflow.OFClient),
76 events: make(chan ofaEvent, 100),
77 }
78
79 if ofa.DeviceListRefreshInterval <= 0 {
80 logger.Warnw("device list refresh internal not valid, setting to default",
81 log.Fields{
82 "value": ofa.DeviceListRefreshInterval.String(),
83 "default": (1 * time.Minute).String()})
84 ofa.DeviceListRefreshInterval = 1 * time.Minute
85 }
86
87 if ofa.ConnectionRetryDelay <= 0 {
88 logger.Warnw("connection retry delay not value, setting to default",
89 log.Fields{
90 "value": ofa.ConnectionRetryDelay.String(),
91 "default": (3 * time.Second).String()})
92 ofa.ConnectionRetryDelay = 3 * time.Second
93 }
94
95 return &ofa, nil
96}
97
98// Run - make the inital connection to voltha and kicks off io streams
99func (ofa *OFAgent) Run(ctx context.Context) {
100
101 logger.Debugw("Starting GRPC - VOLTHA client",
102 log.Fields{
103 "voltha-endpoint": ofa.VolthaApiEndPoint,
Jonathan Hart4b110f62020-03-13 17:36:19 -0700104 "controller-endpoint": ofa.OFControllerEndPoints})
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800105
106 // If the context contains a k8s probe then register services
107 p := probe.GetProbeFromContext(ctx)
108 if p != nil {
109 p.RegisterService("voltha")
110 }
divyadesai81bb7ba2020-03-11 11:45:23 +0000111
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800112 ofa.events <- ofaEventStart
113
114 /*
115 * Two sub-contexts are created here for different purposes so we can
116 * control the lifecyle of processing loops differently.
117 *
118 * volthaCtx - controls those processes that rely on the GRPC
119 * GRPCconnection to voltha and will be restarted when the
120 * GRPC connection is interrupted.
121 * hdlCtx - controls those processes that listen to channels and
122 * process each message. these will likely never be
123 * stopped until the ofagent is stopped.
124 */
125 var volthaCtx, hdlCtx context.Context
126 var volthaDone, hdlDone func()
127 state := ofaStateDisconnected
128
129 for {
130 select {
131 case <-ctx.Done():
132 if volthaDone != nil {
133 volthaDone()
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800134 }
135 if hdlDone != nil {
136 hdlDone()
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800137 }
138 return
139 case event := <-ofa.events:
140 switch event {
141 case ofaEventStart:
142 logger.Debug("ofagent-voltha-start-event")
143
144 // Start the loops that process messages
145 hdlCtx, hdlDone = context.WithCancel(context.Background())
146 go ofa.handlePacketsIn(hdlCtx)
147 go ofa.handleChangeEvents(hdlCtx)
148
149 // Kick off process to attempt to establish
150 // connection to voltha
David K. Bainbridge9cb404e2020-01-28 14:32:29 -0800151 state = ofaStateConnecting
David K. Bainbridgecac73ac2020-02-19 07:00:12 -0800152 go func() {
153 if err := ofa.establishConnectionToVoltha(p); err != nil {
154 logger.Errorw("voltha-connection-failed", log.Fields{"error": err})
155 panic(err)
156 }
157 }()
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800158
159 case ofaEventVolthaConnected:
160 logger.Debug("ofagent-voltha-connect-event")
161
162 // Start the loops that poll from voltha
163 if state != ofaStateConnected {
164 state = ofaStateConnected
165 volthaCtx, volthaDone = context.WithCancel(context.Background())
166 go ofa.receiveChangeEvents(volthaCtx)
167 go ofa.receivePacketsIn(volthaCtx)
168 go ofa.streamPacketOut(volthaCtx)
169 go ofa.synchronizeDeviceList(volthaCtx)
170 }
171
172 case ofaEventVolthaDisconnected:
David K. Bainbridge9cb404e2020-01-28 14:32:29 -0800173 if p != nil {
174 p.UpdateStatus("voltha", probe.ServiceStatusNotReady)
175 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800176 logger.Debug("ofagent-voltha-disconnect-event")
177 if state == ofaStateConnected {
178 state = ofaStateDisconnected
David Bainbridgef8ce7d22020-04-08 12:49:41 -0700179 ofa.volthaClient.Clear()
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800180 volthaDone()
181 volthaDone = nil
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800182 }
David K. Bainbridge9cb404e2020-01-28 14:32:29 -0800183 if state != ofaStateConnecting {
184 state = ofaStateConnecting
David K. Bainbridgecac73ac2020-02-19 07:00:12 -0800185 go func() {
186 if err := ofa.establishConnectionToVoltha(p); err != nil {
Girish Kumare9d76172020-03-20 20:26:04 +0000187 logger.Errorw("voltha-connection-failed", log.Fields{"error": err})
David K. Bainbridgecac73ac2020-02-19 07:00:12 -0800188 panic(err)
189 }
190 }()
David K. Bainbridge9cb404e2020-01-28 14:32:29 -0800191 }
192
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800193 case ofaEventError:
194 logger.Debug("ofagent-error-event")
195 default:
196 logger.Fatalw("ofagent-unknown-event",
197 log.Fields{"event": event})
198 }
199 }
200 }
201}