blob: 4925f4f3e8b5ae3f2eb9d39d9883e614a375c311 [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 Newton98fd8812019-09-23 15:15:02 -0400196 flowModType := uint8(buf[25])
197 switch flowModType {
Don Newtone0d34a82019-11-14 10:58:06 -0500198 case ofp.OFPFCAdd:
Don Newton98fd8812019-09-23 15:15:02 -0400199 flowAdd := header.(*ofp.FlowAdd)
Don Newton7577f072020-01-06 12:41:11 -0500200 go handleFlowAdd(flowAdd, client.DeviceID)
Don Newtone0d34a82019-11-14 10:58:06 -0500201 case ofp.OFPFCModify:
Don Newton98fd8812019-09-23 15:15:02 -0400202 flowMod := header.(*ofp.FlowMod)
Don Newton7577f072020-01-06 12:41:11 -0500203 go handleFlowMod(flowMod, client.DeviceID)
Don Newtone0d34a82019-11-14 10:58:06 -0500204 case ofp.OFPFCModifyStrict:
Don Newton98fd8812019-09-23 15:15:02 -0400205 flowModStrict := header.(*ofp.FlowModifyStrict)
Don Newton7577f072020-01-06 12:41:11 -0500206 go handleFlowModStrict(flowModStrict, client.DeviceID)
Don Newtone0d34a82019-11-14 10:58:06 -0500207 case ofp.OFPFCDelete:
Don Newton98fd8812019-09-23 15:15:02 -0400208 flowDelete := header.(*ofp.FlowDelete)
Don Newton7577f072020-01-06 12:41:11 -0500209 go handleFlowDelete(flowDelete, client.DeviceID)
Don Newtone0d34a82019-11-14 10:58:06 -0500210 case ofp.OFPFCDeleteStrict:
Don Newton98fd8812019-09-23 15:15:02 -0400211 flowDeleteStrict := header.(*ofp.FlowDeleteStrict)
Don Newton7577f072020-01-06 12:41:11 -0500212 go handleFlowDeleteStrict(flowDeleteStrict, client.DeviceID)
Don Newton98fd8812019-09-23 15:15:02 -0400213 }
Don Newtone0d34a82019-11-14 10:58:06 -0500214 case ofp.OFPTStatsRequest:
Don Newton98fd8812019-09-23 15:15:02 -0400215 var statType = uint16(buf[8])<<8 + uint16(buf[9])
Don Newton7577f072020-01-06 12:41:11 -0500216 go handleStatsRequest(header, statType, client.DeviceID, client)
Don Newtone0d34a82019-11-14 10:58:06 -0500217 case ofp.OFPTBarrierRequest:
Don Newton98fd8812019-09-23 15:15:02 -0400218 barRequest := header.(*ofp.BarrierRequest)
Don Newton7577f072020-01-06 12:41:11 -0500219 go handleBarrierRequest(barRequest, client.DeviceID, client)
Don Newtone0d34a82019-11-14 10:58:06 -0500220 case ofp.OFPTRoleRequest:
Don Newton98fd8812019-09-23 15:15:02 -0400221 roleReq := header.(*ofp.RoleRequest)
Don Newton7577f072020-01-06 12:41:11 -0500222 go handleRoleRequest(roleReq, client.DeviceID, client)
Don Newtone0d34a82019-11-14 10:58:06 -0500223 case ofp.OFPTMeterMod:
224 meterMod := header.(*ofp.MeterMod)
Don Newton7577f072020-01-06 12:41:11 -0500225 go handleMeterModRequest(meterMod, client.DeviceID, client)
Don Newton98fd8812019-09-23 15:15:02 -0400226
227 }
228}
229
Don Newton7577f072020-01-06 12:41:11 -0500230//Message created to allow for a single SendMessage
231type Message interface {
Don Newton98fd8812019-09-23 15:15:02 -0400232 Serialize(encoder *goloxi.Encoder) error
233}
234
Don Newton7577f072020-01-06 12:41:11 -0500235//SendMessage sends message to openflow server
236func (client *Client) SendMessage(message Message) error {
237 if settings.GetDebug(client.DeviceID) {
238 js, _ := json.Marshal(message)
239 logger.Debugw("SendMessage called", l.Fields{"DeviceID": client.DeviceID, "Message": js})
240 }
Don Newton98fd8812019-09-23 15:15:02 -0400241 enc := goloxi.NewEncoder()
242 message.Serialize(enc)
Don Newton98fd8812019-09-23 15:15:02 -0400243 for {
Don Newton7577f072020-01-06 12:41:11 -0500244 if client.conn == nil {
245 logger.Warnln("SendMessage Connection is Nil sleeping for 10 milliseconds")
Don Newton98fd8812019-09-23 15:15:02 -0400246 time.Sleep(10 * time.Millisecond)
247 } else {
248 break
249 }
250 }
Don Newton7577f072020-01-06 12:41:11 -0500251 bytes := enc.Bytes()
252 _, err := client.conn.Write(bytes)
Don Newton98fd8812019-09-23 15:15:02 -0400253 if err != nil {
Don Newton7577f072020-01-06 12:41:11 -0500254 jMessage, _ := json.Marshal(message)
255 logger.Errorw("SendMessage failed sending message", l.Fields{"DeviceID": client.DeviceID, "Error": err, "Message": jMessage})
Don Newton98fd8812019-09-23 15:15:02 -0400256 return err
Don Newton98fd8812019-09-23 15:15:02 -0400257 }
258 return nil
259}
Don Newton7577f072020-01-06 12:41:11 -0500260
261//SetGrpcClient store a reference to the grpc client connection
Don Newton98fd8812019-09-23 15:15:02 -0400262func SetGrpcClient(client *pb.VolthaServiceClient) {
263 volthaClient = client
264}
265func getGrpcClient() *pb.VolthaServiceClient {
266 return volthaClient
267}
Don Newton7577f072020-01-06 12:41:11 -0500268
269//SetPacketOutChannel - store the channel to send packet outs to grpc connection
Don Newton98fd8812019-09-23 15:15:02 -0400270func SetPacketOutChannel(pktOutChan chan pb.PacketOut) {
271 packetOutChannel = pktOutChan
272}