blob: 8922f0b166045bb4e83d6e3b920f20a4fba91038 [file] [log] [blame]
Don Newton98fd8812019-09-23 15:15:02 -04001/*
2 Copyright 2017 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 "encoding/json"
21 "fmt"
22 "time"
23
Don Newtone0d34a82019-11-14 10:58:06 -050024 "github.com/donNewtonAlpha/goloxi"
25 ofp "github.com/donNewtonAlpha/goloxi/of13"
Don Newton7577f072020-01-06 12:41:11 -050026 "github.com/opencord/ofagent-go/settings"
27 l "github.com/opencord/voltha-lib-go/v2/pkg/log"
Don Newtonb437c6f2019-12-18 11:51:57 -050028 pb "github.com/opencord/voltha-protos/v2/go/voltha"
Don Newton98fd8812019-09-23 15:15:02 -040029
Don Newton98fd8812019-09-23 15:15:02 -040030 "net"
31)
32
Don Newton98fd8812019-09-23 15:15:02 -040033var volthaClient *pb.VolthaServiceClient
34var packetOutChannel chan pb.PacketOut
Don Newton7577f072020-01-06 12:41:11 -050035var logger, _ = l.AddPackage(l.JSON, l.DebugLevel, nil)
Don Newton98fd8812019-09-23 15:15:02 -040036
Don Newton7577f072020-01-06 12:41:11 -050037//Client structure to hold fields of Openflow Client
Don Newton98fd8812019-09-23 15:15:02 -040038type Client struct {
39 OfServerAddress string
40 Port uint16
Don Newton7577f072020-01-06 12:41:11 -050041 DeviceID string
Don Newton98fd8812019-09-23 15:15:02 -040042 KeepRunning bool
Don Newton7577f072020-01-06 12:41:11 -050043 conn net.Conn
Don Newton98fd8812019-09-23 15:15:02 -040044}
45
Don Newton7577f072020-01-06 12:41:11 -050046//NewClient contstructs a new Openflow Client and then starts up
47func NewClient(ofServerAddress string, port uint16, deviceID string, keepRunning bool) *Client {
Don Newton98fd8812019-09-23 15:15:02 -040048
Don Newton7577f072020-01-06 12:41:11 -050049 client := Client{OfServerAddress: ofServerAddress, Port: port, DeviceID: deviceID, KeepRunning: keepRunning}
Don Newton98fd8812019-09-23 15:15:02 -040050 addressLine := fmt.Sprintf("%s:%d", client.OfServerAddress, client.Port)
51 raddr, e := net.ResolveTCPAddr("tcp", addressLine)
52 if e != nil {
Don Newton7577f072020-01-06 12:41:11 -050053 logger.Fatalw("openflowClient Start unable to resolve address", l.Fields{"Address": addressLine})
Don Newton98fd8812019-09-23 15:15:02 -040054 }
Don Newton7577f072020-01-06 12:41:11 -050055 connection, e := net.DialTCP("tcp", nil, raddr)
56 client.conn = connection
57 if e != nil {
58 logger.Fatalf("openflowClient Unable to connect to voltha @ %v exiting", raddr)
59 }
60 client.sayHello()
61 return &client
62}
63
64//End - set keepRunning to false so start loop exits
65func (client *Client) End() {
66 client.KeepRunning = false
67}
68
69//Start run loop for the openflow client
70func (client *Client) Start() {
71
Don Newton98fd8812019-09-23 15:15:02 -040072 for {
73 if client.KeepRunning {
Don Newton7577f072020-01-06 12:41:11 -050074 defer client.conn.Close()
Don Newton98fd8812019-09-23 15:15:02 -040075 for {
Don Newton7577f072020-01-06 12:41:11 -050076 defer func() {
77
78 if r := recover(); r != nil {
79 err := r.(error)
80 fmt.Printf("Caught error in client.Start() %v \n ", err)
81 }
82 }()
83
Don Newtonb437c6f2019-12-18 11:51:57 -050084 if !client.KeepRunning {
85 return
86 }
Don Newton98fd8812019-09-23 15:15:02 -040087 buf := make([]byte, 1500)
Don Newton7577f072020-01-06 12:41:11 -050088 read, e := client.conn.Read(buf)
89 if settings.GetDebug(client.DeviceID) {
90 fmt.Printf("conn.Read read %d bytes\n", read)
91 }
92 if read < 8 {
93 continue
94 }
95
Don Newton98fd8812019-09-23 15:15:02 -040096 if e != nil {
Don Newton7577f072020-01-06 12:41:11 -050097 logger.Errorw("Voltha connection has died", l.Fields{"DeviceID": client.DeviceID, "Error": e})
Don Newton98fd8812019-09-23 15:15:02 -040098 break
99 }
100 decoder := goloxi.NewDecoder(buf)
Don Newton98fd8812019-09-23 15:15:02 -0400101 header, e := ofp.DecodeHeader(decoder)
Don Newton98fd8812019-09-23 15:15:02 -0400102
103 if e != nil {
Don Newton7577f072020-01-06 12:41:11 -0500104 js, _ := json.Marshal(decoder)
105 logger.Errorw("DecodeHeader threw error", l.Fields{"DeviceID": client.DeviceID, "Decoder": js, "Error": e})
Don Newton98fd8812019-09-23 15:15:02 -0400106 }
Don Newton7577f072020-01-06 12:41:11 -0500107 if settings.GetDebug(client.DeviceID) {
108 js, _ := json.Marshal(header)
109 logger.Debugw("Header Decode", l.Fields{"DeviceID": client.DeviceID, "Header": js})
110 }
Don Newton98fd8812019-09-23 15:15:02 -0400111 client.parseHeader(header, buf) //first one is ready
112 len := header.GetLength()
113 if len < uint16(read) {
Don Newton98fd8812019-09-23 15:15:02 -0400114 for {
115 read = read - int(len)
116 newBuf := buf[len:]
117 decoder = goloxi.NewDecoder(newBuf)
118 newHeader, e := ofp.DecodeHeader(decoder)
Don Newton98fd8812019-09-23 15:15:02 -0400119 if e != nil {
Don Newton7577f072020-01-06 12:41:11 -0500120 js, _ := json.Marshal(decoder)
121 logger.Errorw("DecodeHeader threw error", l.Fields{"DeviceID": client.DeviceID, "Decoder": js, "Error": e})
122 }
123 if e != nil {
124 js, _ := json.Marshal(decoder)
125 logger.Errorw("DecodeHeader threw error", l.Fields{"DeviceID": client.DeviceID, "Decoder": js, "Error": e})
126 }
127 if settings.GetDebug(client.DeviceID) {
128 js, _ := json.Marshal(header)
129 logger.Debugw("Header Decode", l.Fields{"DeviceID": client.DeviceID, "Header": js})
Don Newton98fd8812019-09-23 15:15:02 -0400130 }
131 len = newHeader.GetLength()
132 client.parseHeader(newHeader, newBuf)
133 if read == int(len) {
Don Newton98fd8812019-09-23 15:15:02 -0400134 break
Don Newton98fd8812019-09-23 15:15:02 -0400135 }
136 buf = newBuf
137 }
138 }
Don Newton98fd8812019-09-23 15:15:02 -0400139 }
140 }
141 break
142 }
143}
Don Newtonb437c6f2019-12-18 11:51:57 -0500144func (client *Client) sayHello() {
Don Newtonb437c6f2019-12-18 11:51:57 -0500145 hello := ofp.NewHello()
146 hello.Xid = uint32(GetXid())
147 var elements []ofp.IHelloElem
Don Newtonb437c6f2019-12-18 11:51:57 -0500148 elem := ofp.NewHelloElemVersionbitmap()
149 elem.SetType(ofp.OFPHETVersionbitmap)
150 elem.SetLength(8)
151 var bitmap = ofp.Uint32{Value: 16}
152 bitmaps := []*ofp.Uint32{&bitmap}
Don Newtonb437c6f2019-12-18 11:51:57 -0500153 elem.SetBitmaps(bitmaps)
Don Newtonb437c6f2019-12-18 11:51:57 -0500154 elements = append(elements, elem)
Don Newtonb437c6f2019-12-18 11:51:57 -0500155 hello.SetElements(elements)
Don Newton7577f072020-01-06 12:41:11 -0500156 if settings.GetDebug(client.DeviceID) {
157 js, _ := json.Marshal(hello)
158 logger.Debugw("sayHello Called", l.Fields{"DeviceID": client.DeviceID, "HelloMessage": js})
159 }
Don Newtonb437c6f2019-12-18 11:51:57 -0500160 e := client.SendMessage(hello)
161 if e != nil {
Don Newton7577f072020-01-06 12:41:11 -0500162 logger.Fatalw("Failed saying hello to Openflow Server, unable to proceed",
163 l.Fields{"DeviceID": client.DeviceID, "Error": e})
Don Newtonb437c6f2019-12-18 11:51:57 -0500164 }
165}
Don Newton98fd8812019-09-23 15:15:02 -0400166func (client *Client) parseHeader(header ofp.IHeader, buf []byte) {
Don Newton98fd8812019-09-23 15:15:02 -0400167 switch header.GetType() {
Don Newtone0d34a82019-11-14 10:58:06 -0500168 case ofp.OFPTHello:
Don Newtonb437c6f2019-12-18 11:51:57 -0500169 //x := header.(*ofp.Hello)
Don Newtone0d34a82019-11-14 10:58:06 -0500170 case ofp.OFPTError:
Don Newton98fd8812019-09-23 15:15:02 -0400171 errMsg := header.(*ofp.ErrorMsg)
Don Newton7577f072020-01-06 12:41:11 -0500172 go handleErrMsg(errMsg, client.DeviceID)
Don Newtone0d34a82019-11-14 10:58:06 -0500173 case ofp.OFPTEchoRequest:
Don Newton98fd8812019-09-23 15:15:02 -0400174 echoReq := header.(*ofp.EchoRequest)
Don Newton7577f072020-01-06 12:41:11 -0500175 go handleEchoRequest(echoReq, client.DeviceID, client)
Don Newtone0d34a82019-11-14 10:58:06 -0500176 case ofp.OFPTEchoReply:
177 case ofp.OFPTExperimenter:
178 case ofp.OFPTFeaturesRequest:
Don Newton98fd8812019-09-23 15:15:02 -0400179 featReq := header.(*ofp.FeaturesRequest)
Don Newton7577f072020-01-06 12:41:11 -0500180 go handleFeatureRequest(featReq, client.DeviceID, client)
Don Newtone0d34a82019-11-14 10:58:06 -0500181 case ofp.OFPTFeaturesReply:
182 case ofp.OFPTGetConfigRequest:
Don Newton98fd8812019-09-23 15:15:02 -0400183 configReq := header.(*ofp.GetConfigRequest)
Don Newton7577f072020-01-06 12:41:11 -0500184 go handleGetConfigRequest(configReq, client.DeviceID, client)
Don Newtone0d34a82019-11-14 10:58:06 -0500185 case ofp.OFPTGetConfigReply:
186 case ofp.OFPTSetConfig:
Don Newton98fd8812019-09-23 15:15:02 -0400187 setConf := header.(*ofp.SetConfig)
Don Newton7577f072020-01-06 12:41:11 -0500188 go handleSetConfig(setConf, client.DeviceID)
Don Newtone0d34a82019-11-14 10:58:06 -0500189 case ofp.OFPTPacketIn:
190 case ofp.OFPTFlowRemoved:
191 case ofp.OFPTPortStatus:
192 case ofp.OFPTPacketOut:
Don Newton98fd8812019-09-23 15:15:02 -0400193 packetOut := header.(*ofp.PacketOut)
Don Newton7577f072020-01-06 12:41:11 -0500194 go handlePacketOut(packetOut, client.DeviceID)
Don Newtone0d34a82019-11-14 10:58:06 -0500195 case ofp.OFPTFlowMod:
Don Newton6f6c8662020-01-15 14:44:49 -0500196 /* Not using go routine to handle flow* messages or barrier requests
197 onos typically issues barrier requests just before a flow* message.
198 by handling in this thread I ensure all flow* are handled when barrier
199 request is issued.
200 */
Don Newton98fd8812019-09-23 15:15:02 -0400201 flowModType := uint8(buf[25])
202 switch flowModType {
Don Newtone0d34a82019-11-14 10:58:06 -0500203 case ofp.OFPFCAdd:
Don Newton98fd8812019-09-23 15:15:02 -0400204 flowAdd := header.(*ofp.FlowAdd)
Don Newton6f6c8662020-01-15 14:44:49 -0500205 handleFlowAdd(flowAdd, client.DeviceID)
Don Newtone0d34a82019-11-14 10:58:06 -0500206 case ofp.OFPFCModify:
Don Newton98fd8812019-09-23 15:15:02 -0400207 flowMod := header.(*ofp.FlowMod)
Don Newton6f6c8662020-01-15 14:44:49 -0500208 handleFlowMod(flowMod, client.DeviceID)
Don Newtone0d34a82019-11-14 10:58:06 -0500209 case ofp.OFPFCModifyStrict:
Don Newton98fd8812019-09-23 15:15:02 -0400210 flowModStrict := header.(*ofp.FlowModifyStrict)
Don Newton6f6c8662020-01-15 14:44:49 -0500211 handleFlowModStrict(flowModStrict, client.DeviceID)
Don Newtone0d34a82019-11-14 10:58:06 -0500212 case ofp.OFPFCDelete:
Don Newton98fd8812019-09-23 15:15:02 -0400213 flowDelete := header.(*ofp.FlowDelete)
Don Newton6f6c8662020-01-15 14:44:49 -0500214 handleFlowDelete(flowDelete, client.DeviceID)
Don Newtone0d34a82019-11-14 10:58:06 -0500215 case ofp.OFPFCDeleteStrict:
Don Newton98fd8812019-09-23 15:15:02 -0400216 flowDeleteStrict := header.(*ofp.FlowDeleteStrict)
Don Newton6f6c8662020-01-15 14:44:49 -0500217 handleFlowDeleteStrict(flowDeleteStrict, client.DeviceID)
Don Newton98fd8812019-09-23 15:15:02 -0400218 }
Don Newtone0d34a82019-11-14 10:58:06 -0500219 case ofp.OFPTStatsRequest:
Don Newton98fd8812019-09-23 15:15:02 -0400220 var statType = uint16(buf[8])<<8 + uint16(buf[9])
Don Newton7577f072020-01-06 12:41:11 -0500221 go handleStatsRequest(header, statType, client.DeviceID, client)
Don Newtone0d34a82019-11-14 10:58:06 -0500222 case ofp.OFPTBarrierRequest:
Don Newton6f6c8662020-01-15 14:44:49 -0500223 /* See note above at case ofp.OFPTFlowMod:*/
Don Newton98fd8812019-09-23 15:15:02 -0400224 barRequest := header.(*ofp.BarrierRequest)
Don Newton6f6c8662020-01-15 14:44:49 -0500225 handleBarrierRequest(barRequest, client.DeviceID, client)
Don Newtone0d34a82019-11-14 10:58:06 -0500226 case ofp.OFPTRoleRequest:
Don Newton98fd8812019-09-23 15:15:02 -0400227 roleReq := header.(*ofp.RoleRequest)
Don Newton7577f072020-01-06 12:41:11 -0500228 go handleRoleRequest(roleReq, client.DeviceID, client)
Don Newtone0d34a82019-11-14 10:58:06 -0500229 case ofp.OFPTMeterMod:
230 meterMod := header.(*ofp.MeterMod)
Don Newton7577f072020-01-06 12:41:11 -0500231 go handleMeterModRequest(meterMod, client.DeviceID, client)
Don Newton98fd8812019-09-23 15:15:02 -0400232
233 }
234}
235
Don Newton7577f072020-01-06 12:41:11 -0500236//Message created to allow for a single SendMessage
237type Message interface {
Don Newton98fd8812019-09-23 15:15:02 -0400238 Serialize(encoder *goloxi.Encoder) error
239}
240
Don Newton7577f072020-01-06 12:41:11 -0500241//SendMessage sends message to openflow server
242func (client *Client) SendMessage(message Message) error {
243 if settings.GetDebug(client.DeviceID) {
244 js, _ := json.Marshal(message)
245 logger.Debugw("SendMessage called", l.Fields{"DeviceID": client.DeviceID, "Message": js})
246 }
Don Newton98fd8812019-09-23 15:15:02 -0400247 enc := goloxi.NewEncoder()
248 message.Serialize(enc)
Don Newton98fd8812019-09-23 15:15:02 -0400249 for {
Don Newton7577f072020-01-06 12:41:11 -0500250 if client.conn == nil {
251 logger.Warnln("SendMessage Connection is Nil sleeping for 10 milliseconds")
Don Newton98fd8812019-09-23 15:15:02 -0400252 time.Sleep(10 * time.Millisecond)
253 } else {
254 break
255 }
256 }
Don Newton7577f072020-01-06 12:41:11 -0500257 bytes := enc.Bytes()
258 _, err := client.conn.Write(bytes)
Don Newton98fd8812019-09-23 15:15:02 -0400259 if err != nil {
Don Newton7577f072020-01-06 12:41:11 -0500260 jMessage, _ := json.Marshal(message)
261 logger.Errorw("SendMessage failed sending message", l.Fields{"DeviceID": client.DeviceID, "Error": err, "Message": jMessage})
Don Newton98fd8812019-09-23 15:15:02 -0400262 return err
Don Newton98fd8812019-09-23 15:15:02 -0400263 }
264 return nil
265}
Don Newton7577f072020-01-06 12:41:11 -0500266
267//SetGrpcClient store a reference to the grpc client connection
Don Newton98fd8812019-09-23 15:15:02 -0400268func SetGrpcClient(client *pb.VolthaServiceClient) {
269 volthaClient = client
270}
271func getGrpcClient() *pb.VolthaServiceClient {
272 return volthaClient
273}
Don Newton7577f072020-01-06 12:41:11 -0500274
275//SetPacketOutChannel - store the channel to send packet outs to grpc connection
Don Newton98fd8812019-09-23 15:15:02 -0400276func SetPacketOutChannel(pktOutChan chan pb.PacketOut) {
277 packetOutChannel = pktOutChan
278}