blob: aeac406cbd0e7a3d52704dbeacef98187c5112e7 [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 openflow
18
19import (
20 "context"
David K. Bainbridge157bdab2020-01-16 14:38:05 -080021 "errors"
David K. Bainbridge157bdab2020-01-16 14:38:05 -080022 ofp "github.com/donNewtonAlpha/goloxi/of13"
David K. Bainbridgeaea73cd2020-01-27 10:44:50 -080023 "github.com/opencord/voltha-lib-go/v3/pkg/log"
24 "github.com/opencord/voltha-protos/v3/go/voltha"
Jonathan Hart4b110f62020-03-13 17:36:19 -070025 "sync"
David K. Bainbridge157bdab2020-01-16 14:38:05 -080026 "time"
27)
28
David K. Bainbridge9cb404e2020-01-28 14:32:29 -080029var NoVolthaConnectionError = errors.New("no-voltha-connection")
David K. Bainbridge157bdab2020-01-16 14:38:05 -080030
31type ofcEvent byte
32type ofcState byte
Jonathan Hart4b110f62020-03-13 17:36:19 -070033type ofcRole byte
David K. Bainbridge157bdab2020-01-16 14:38:05 -080034
35const (
36 ofcEventStart = ofcEvent(iota)
David K. Bainbridge55376262020-01-22 23:28:27 -080037 ofcEventConnect
38 ofcEventDisconnect
39 ofcEventStop
David K. Bainbridge157bdab2020-01-16 14:38:05 -080040
David K. Bainbridge55376262020-01-22 23:28:27 -080041 ofcStateCreated = ofcState(iota)
42 ofcStateStarted
43 ofcStateConnected
David K. Bainbridge157bdab2020-01-16 14:38:05 -080044 ofcStateDisconnected
David K. Bainbridge55376262020-01-22 23:28:27 -080045 ofcStateStopped
Jonathan Hart4b110f62020-03-13 17:36:19 -070046
47 ofcRoleNone = ofcRole(iota)
48 ofcRoleEqual
49 ofcRoleMaster
50 ofcRoleSlave
David K. Bainbridge157bdab2020-01-16 14:38:05 -080051)
52
David K. Bainbridge55376262020-01-22 23:28:27 -080053func (e ofcEvent) String() string {
54 switch e {
55 case ofcEventStart:
56 return "ofc-event-start"
57 case ofcEventConnect:
58 return "ofc-event-connected"
59 case ofcEventDisconnect:
60 return "ofc-event-disconnected"
61 case ofcEventStop:
62 return "ofc-event-stop"
63 default:
64 return "ofc-event-unknown"
65 }
66}
67
68func (s ofcState) String() string {
69 switch s {
70 case ofcStateCreated:
71 return "ofc-state-created"
72 case ofcStateStarted:
73 return "ofc-state-started"
74 case ofcStateConnected:
75 return "ofc-state-connected"
76 case ofcStateDisconnected:
77 return "ofc-state-disconnected"
78 case ofcStateStopped:
79 return "ofc-state-stopped"
80 default:
81 return "ofc-state-unknown"
82 }
83}
84
85// OFClient the configuration and operational state of a connection to an
86// openflow controller
David K. Bainbridge157bdab2020-01-16 14:38:05 -080087type OFClient struct {
Jonathan Hart4b110f62020-03-13 17:36:19 -070088 OFControllerEndPoints []string
89 DeviceID string
90 VolthaClient voltha.VolthaServiceClient
91 PacketOutChannel chan *voltha.PacketOut
92 ConnectionMaxRetries int
93 ConnectionRetryDelay time.Duration
David K. Bainbridge157bdab2020-01-16 14:38:05 -080094
Jonathan Hart4b110f62020-03-13 17:36:19 -070095 // map of endpoint to OF connection
96 connections map[string]*OFConnection
97
98 // global role state for device
99 generationIsDefined bool
100 generationID uint64
101 roleLock sync.Mutex
102}
103
104type RoleManager interface {
105 UpdateRoles(from string, request *ofp.RoleRequest) bool
106}
107
108func distance(a uint64, b uint64) int64 {
109 return (int64)(a - b)
110}
111
112// UpdateRoles validates a role request and updates role state for connections where it changed
113func (ofc *OFClient) UpdateRoles(from string, request *ofp.RoleRequest) bool {
114 log.Debug("updating role", log.Fields{
115 "from": from,
116 "to": request.Role,
117 "id": request.GenerationId})
118
119 ofc.roleLock.Lock()
120 defer ofc.roleLock.Unlock()
121
122 if request.Role == ofp.OFPCRRoleEqual {
123 // equal request doesn't care about generation ID and always succeeds
124 connection := ofc.connections[from]
125 connection.role = ofcRoleEqual
126 return true
127 }
128
129 if ofc.generationIsDefined && distance(request.GenerationId, ofc.generationID) < 0 {
130 // generation ID is not valid
131 return false
132 } else {
133 ofc.generationID = request.GenerationId
134 ofc.generationIsDefined = true
135
136 if request.Role == ofp.OFPCRRoleMaster {
137 // master is potentially changing, find the existing master and set it to slave
138 for endpoint, connection := range ofc.connections {
139 if endpoint == from {
140 connection.role = ofcRoleMaster
141 } else if connection.role == ofcRoleMaster {
142 // the old master should be set to slave
143 connection.role = ofcRoleSlave
144 }
145 }
146 return true
147 } else if request.Role == ofp.OFPCRRoleSlave {
148 connection := ofc.connections[from]
149 connection.role = ofcRoleSlave
150 return true
151 }
152 }
153
154 return false
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800155}
156
David K. Bainbridge55376262020-01-22 23:28:27 -0800157// NewClient returns an initialized OFClient instance based on the configuration
158// specified
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800159func NewOFClient(config *OFClient) *OFClient {
160
161 ofc := OFClient{
Jonathan Hart4b110f62020-03-13 17:36:19 -0700162 DeviceID: config.DeviceID,
163 OFControllerEndPoints: config.OFControllerEndPoints,
164 VolthaClient: config.VolthaClient,
165 PacketOutChannel: config.PacketOutChannel,
166 ConnectionMaxRetries: config.ConnectionMaxRetries,
167 ConnectionRetryDelay: config.ConnectionRetryDelay,
168 connections: make(map[string]*OFConnection),
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800169 }
170
171 if ofc.ConnectionRetryDelay <= 0 {
172 logger.Warnw("connection retry delay not valid, setting to default",
173 log.Fields{
174 "device-id": ofc.DeviceID,
175 "value": ofc.ConnectionRetryDelay.String(),
176 "default": (3 * time.Second).String()})
177 ofc.ConnectionRetryDelay = 3 * time.Second
178 }
179 return &ofc
180}
181
David K. Bainbridge55376262020-01-22 23:28:27 -0800182// Stop initiates a shutdown of the OFClient
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800183func (ofc *OFClient) Stop() {
Jonathan Hart4b110f62020-03-13 17:36:19 -0700184 for _, connection := range ofc.connections {
185 connection.events <- ofcEventStop
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800186 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800187}
188
189func (ofc *OFClient) Run(ctx context.Context) {
190
Jonathan Hart4b110f62020-03-13 17:36:19 -0700191 for _, endpoint := range ofc.OFControllerEndPoints {
192 connection := &OFConnection{
193 OFControllerEndPoint: endpoint,
194 DeviceID: ofc.DeviceID,
195 VolthaClient: ofc.VolthaClient,
196 PacketOutChannel: ofc.PacketOutChannel,
197 ConnectionMaxRetries: ofc.ConnectionMaxRetries,
198 ConnectionRetryDelay: ofc.ConnectionRetryDelay,
199 role: ofcRoleNone,
200 roleManager: ofc,
201 events: make(chan ofcEvent, 10),
202 sendChannel: make(chan Message, 100),
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800203 }
Jonathan Hart4b110f62020-03-13 17:36:19 -0700204
205 ofc.connections[endpoint] = connection
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800206 }
207
Jonathan Hart4b110f62020-03-13 17:36:19 -0700208 for _, connection := range ofc.connections {
209 go connection.Run(ctx)
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800210 }
211}
212
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800213func (ofc *OFClient) SendMessage(message Message) error {
Jonathan Hart4b110f62020-03-13 17:36:19 -0700214 for _, connection := range ofc.connections {
215 if connection.role == ofcRoleMaster || connection.role == ofcRoleEqual {
216 err := connection.SendMessage(message)
217 if err != nil {
218 return err
219 }
220 }
221 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800222 return nil
223}