khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 1 | /* |
| 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 | */ |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 16 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 17 | package device |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 18 | |
| 19 | import ( |
| 20 | "context" |
Matteo Scandolo | 360605d | 2019-11-05 18:29:17 -0800 | [diff] [blame] | 21 | "encoding/hex" |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 22 | "fmt" |
David Bainbridge | d1afd66 | 2020-03-26 18:27:41 -0700 | [diff] [blame] | 23 | "sync" |
| 24 | "time" |
| 25 | |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 26 | "github.com/gogo/protobuf/proto" |
sbarbari | 17d7e22 | 2019-11-05 10:02:29 -0500 | [diff] [blame] | 27 | "github.com/opencord/voltha-go/db/model" |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 28 | fd "github.com/opencord/voltha-go/rw_core/flowdecomposition" |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 29 | "github.com/opencord/voltha-go/rw_core/route" |
Scott Baker | b671a86 | 2019-10-24 10:53:40 -0700 | [diff] [blame] | 30 | coreutils "github.com/opencord/voltha-go/rw_core/utils" |
serkant.uluderya | 2ae470f | 2020-01-21 11:13:09 -0800 | [diff] [blame] | 31 | fu "github.com/opencord/voltha-lib-go/v3/pkg/flows" |
| 32 | "github.com/opencord/voltha-lib-go/v3/pkg/log" |
| 33 | ic "github.com/opencord/voltha-protos/v3/go/inter_container" |
| 34 | ofp "github.com/opencord/voltha-protos/v3/go/openflow_13" |
| 35 | "github.com/opencord/voltha-protos/v3/go/voltha" |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 36 | "google.golang.org/grpc/codes" |
| 37 | "google.golang.org/grpc/status" |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 38 | ) |
| 39 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 40 | // LogicalAgent represent attributes of logical device agent |
| 41 | type LogicalAgent struct { |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 42 | logicalDeviceID string |
David Bainbridge | d1afd66 | 2020-03-26 18:27:41 -0700 | [diff] [blame] | 43 | serialNumber string |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 44 | rootDeviceID string |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 45 | deviceMgr *Manager |
| 46 | ldeviceMgr *LogicalManager |
khenaidoo | 3306c99 | 2019-05-24 16:57:35 -0400 | [diff] [blame] | 47 | clusterDataProxy *model.Proxy |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 48 | stopped bool |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 49 | deviceRoutes *route.DeviceRoutes |
khenaidoo | 3306c99 | 2019-05-24 16:57:35 -0400 | [diff] [blame] | 50 | logicalPortsNo map[uint32]bool //value is true for NNI port |
| 51 | lockLogicalPortsNo sync.RWMutex |
| 52 | flowDecomposer *fd.FlowDecomposer |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 53 | defaultTimeout time.Duration |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 54 | logicalDevice *voltha.LogicalDevice |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 55 | requestQueue *coreutils.RequestQueue |
| 56 | startOnce sync.Once |
| 57 | stopOnce sync.Once |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame] | 58 | |
| 59 | meters map[uint32]*MeterChunk |
| 60 | meterLock sync.RWMutex |
| 61 | flows map[uint64]*FlowChunk |
| 62 | flowLock sync.RWMutex |
| 63 | groups map[uint32]*GroupChunk |
| 64 | groupLock sync.RWMutex |
| 65 | } |
| 66 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 67 | func newLogicalDeviceAgent(id string, sn string, deviceID string, ldeviceMgr *LogicalManager, |
khenaidoo | 0db4c81 | 2020-05-27 15:27:30 -0400 | [diff] [blame^] | 68 | deviceMgr *Manager, cdProxy *model.Proxy, defaultTimeout time.Duration) *LogicalAgent { |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 69 | var agent LogicalAgent |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 70 | agent.logicalDeviceID = id |
David Bainbridge | d1afd66 | 2020-03-26 18:27:41 -0700 | [diff] [blame] | 71 | agent.serialNumber = sn |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 72 | agent.rootDeviceID = deviceID |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 73 | agent.deviceMgr = deviceMgr |
khenaidoo | 9a46896 | 2018-09-19 15:33:13 -0400 | [diff] [blame] | 74 | agent.clusterDataProxy = cdProxy |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 75 | agent.ldeviceMgr = ldeviceMgr |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 76 | agent.flowDecomposer = fd.NewFlowDecomposer(agent.deviceMgr) |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 77 | agent.logicalPortsNo = make(map[uint32]bool) |
khenaidoo | 0db4c81 | 2020-05-27 15:27:30 -0400 | [diff] [blame^] | 78 | agent.defaultTimeout = defaultTimeout |
Kent Hagerman | 730cbdf | 2020-03-31 12:22:08 -0400 | [diff] [blame] | 79 | agent.requestQueue = coreutils.NewRequestQueue() |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame] | 80 | agent.meters = make(map[uint32]*MeterChunk) |
| 81 | agent.flows = make(map[uint64]*FlowChunk) |
| 82 | agent.groups = make(map[uint32]*GroupChunk) |
khenaidoo | 0db4c81 | 2020-05-27 15:27:30 -0400 | [diff] [blame^] | 83 | agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.getDevice) |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 84 | return &agent |
| 85 | } |
| 86 | |
khenaidoo | 4d4802d | 2018-10-04 21:59:49 -0400 | [diff] [blame] | 87 | // start creates the logical device and add it to the data model |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 88 | func (agent *LogicalAgent) start(ctx context.Context, loadFromDB bool) error { |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 89 | needToStart := false |
| 90 | if agent.startOnce.Do(func() { needToStart = true }); !needToStart { |
| 91 | return nil |
| 92 | } |
| 93 | |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 94 | logger.Infow("starting-logical_device-agent", log.Fields{"logical-device-id": agent.logicalDeviceID, "load-from-db": loadFromDB}) |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 95 | |
| 96 | var startSucceeded bool |
| 97 | defer func() { |
| 98 | if !startSucceeded { |
| 99 | if err := agent.stop(ctx); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 100 | logger.Errorw("failed-to-cleanup-after-unsuccessful-start", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err}) |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 101 | } |
| 102 | } |
| 103 | }() |
| 104 | |
khenaidoo | 297cd25 | 2019-02-07 22:10:23 -0500 | [diff] [blame] | 105 | var ld *voltha.LogicalDevice |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 106 | if !loadFromDB { |
khenaidoo | 7e3d8f1 | 2019-08-02 16:06:30 -0400 | [diff] [blame] | 107 | //Build the logical device based on information retrieved from the device adapter |
| 108 | var switchCap *ic.SwitchCapability |
khenaidoo | 297cd25 | 2019-02-07 22:10:23 -0500 | [diff] [blame] | 109 | var err error |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 110 | if switchCap, err = agent.deviceMgr.getSwitchCapability(ctx, agent.rootDeviceID); err != nil { |
khenaidoo | 7e3d8f1 | 2019-08-02 16:06:30 -0400 | [diff] [blame] | 111 | return err |
| 112 | } |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 113 | ld = &voltha.LogicalDevice{Id: agent.logicalDeviceID, RootDeviceId: agent.rootDeviceID} |
khenaidoo | 297cd25 | 2019-02-07 22:10:23 -0500 | [diff] [blame] | 114 | |
| 115 | // Create the datapath ID (uint64) using the logical device ID (based on the MAC Address) |
| 116 | var datapathID uint64 |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 117 | if datapathID, err = coreutils.CreateDataPathID(agent.serialNumber); err != nil { |
khenaidoo | 297cd25 | 2019-02-07 22:10:23 -0500 | [diff] [blame] | 118 | return err |
| 119 | } |
| 120 | ld.DatapathId = datapathID |
khenaidoo | 7e3d8f1 | 2019-08-02 16:06:30 -0400 | [diff] [blame] | 121 | ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc) |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 122 | logger.Debugw("Switch-capability", log.Fields{"Desc": ld.Desc, "fromAd": switchCap.Desc}) |
khenaidoo | 7e3d8f1 | 2019-08-02 16:06:30 -0400 | [diff] [blame] | 123 | ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures) |
khenaidoo | 297cd25 | 2019-02-07 22:10:23 -0500 | [diff] [blame] | 124 | ld.Flows = &ofp.Flows{Items: nil} |
| 125 | ld.FlowGroups = &ofp.FlowGroups{Items: nil} |
khenaidoo | 4908535 | 2020-01-13 19:15:43 -0500 | [diff] [blame] | 126 | ld.Ports = []*voltha.LogicalPort{} |
khenaidoo | 297cd25 | 2019-02-07 22:10:23 -0500 | [diff] [blame] | 127 | |
khenaidoo | 297cd25 | 2019-02-07 22:10:23 -0500 | [diff] [blame] | 128 | // Save the logical device |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 129 | if err := agent.clusterDataProxy.AddWithID(ctx, "logical_devices", ld.Id, ld); err != nil { |
| 130 | logger.Errorw("failed-to-add-logical-device", log.Fields{"logical-device-id": agent.logicalDeviceID}) |
Thomas Lee S | e5a4401 | 2019-11-07 20:32:24 +0530 | [diff] [blame] | 131 | return err |
| 132 | } |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 133 | logger.Debugw("logicaldevice-created", log.Fields{"logical-device-id": agent.logicalDeviceID, "root-id": ld.RootDeviceId}) |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 134 | |
| 135 | agent.logicalDevice = proto.Clone(ld).(*voltha.LogicalDevice) |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 136 | |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 137 | // Setup the logicalports - internal processing, no need to propagate the client context |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 138 | go func() { |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 139 | err := agent.setupLogicalPorts(context.Background()) |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 140 | if err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 141 | logger.Errorw("unable-to-setup-logical-ports", log.Fields{"error": err}) |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 142 | } |
| 143 | }() |
khenaidoo | 297cd25 | 2019-02-07 22:10:23 -0500 | [diff] [blame] | 144 | } else { |
| 145 | // load from dB - the logical may not exist at this time. On error, just return and the calling function |
| 146 | // will destroy this agent. |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 147 | ld := &voltha.LogicalDevice{} |
| 148 | have, err := agent.clusterDataProxy.Get(ctx, "logical_devices/"+agent.logicalDeviceID, ld) |
Thomas Lee S | e5a4401 | 2019-11-07 20:32:24 +0530 | [diff] [blame] | 149 | if err != nil { |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 150 | return err |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 151 | } else if !have { |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 152 | return status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceID) |
khenaidoo | 297cd25 | 2019-02-07 22:10:23 -0500 | [diff] [blame] | 153 | } |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 154 | |
khenaidoo | 8c3303d | 2019-02-13 14:59:39 -0500 | [diff] [blame] | 155 | // Update the root device Id |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 156 | agent.rootDeviceID = ld.RootDeviceId |
khenaidoo | 3d3b8c2 | 2019-05-22 18:10:39 -0400 | [diff] [blame] | 157 | |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 158 | // Update the last data |
| 159 | agent.logicalDevice = proto.Clone(ld).(*voltha.LogicalDevice) |
| 160 | |
khenaidoo | 3d3b8c2 | 2019-05-22 18:10:39 -0400 | [diff] [blame] | 161 | // Setup the local list of logical ports |
| 162 | agent.addLogicalPortsToMap(ld.Ports) |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame] | 163 | // load the flows, meters and groups from KV to cache |
| 164 | agent.loadFlows(ctx) |
| 165 | agent.loadMeters(ctx) |
| 166 | agent.loadGroups(ctx) |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 167 | } |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 168 | |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 169 | // Setup the device routes. Building routes may fail if the pre-conditions are not satisfied (e.g. no PON ports present) |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 170 | if loadFromDB { |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 171 | go func() { |
| 172 | if err := agent.buildRoutes(context.Background()); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 173 | logger.Warn("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err}) |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 174 | } |
| 175 | }() |
khenaidoo | 4c9e559 | 2019-09-09 16:20:41 -0400 | [diff] [blame] | 176 | } |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 177 | startSucceeded = true |
| 178 | |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 179 | return nil |
| 180 | } |
| 181 | |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 182 | // stop stops the logical device agent. This removes the logical device from the data model. |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 183 | func (agent *LogicalAgent) stop(ctx context.Context) error { |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 184 | var returnErr error |
| 185 | agent.stopOnce.Do(func() { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 186 | logger.Info("stopping-logical_device-agent") |
khenaidoo | 8c3303d | 2019-02-13 14:59:39 -0500 | [diff] [blame] | 187 | |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 188 | if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil { |
| 189 | // This should never happen - an error is returned only if the agent is stopped and an agent is only stopped once. |
| 190 | returnErr = err |
| 191 | return |
| 192 | } |
| 193 | defer agent.requestQueue.RequestComplete() |
| 194 | |
| 195 | //Remove the logical device from the model |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 196 | if err := agent.clusterDataProxy.Remove(ctx, "logical_devices/"+agent.logicalDeviceID); err != nil { |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 197 | returnErr = err |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 198 | } else { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 199 | logger.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceID}) |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 200 | } |
| 201 | |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 202 | agent.stopped = true |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 203 | |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 204 | logger.Info("logical_device-agent-stopped") |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 205 | }) |
| 206 | return returnErr |
khenaidoo | 4d4802d | 2018-10-04 21:59:49 -0400 | [diff] [blame] | 207 | } |
| 208 | |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 209 | // GetLogicalDevice returns the latest logical device data |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 210 | func (agent *LogicalAgent) GetLogicalDevice(ctx context.Context) (*voltha.LogicalDevice, error) { |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 211 | if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil { |
| 212 | return nil, err |
| 213 | } |
| 214 | defer agent.requestQueue.RequestComplete() |
| 215 | return proto.Clone(agent.logicalDevice).(*voltha.LogicalDevice), nil |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 216 | } |
| 217 | |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 218 | // getLogicalDeviceWithoutLock returns a cloned logical device to a function that already holds the agent lock. |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 219 | func (agent *LogicalAgent) getLogicalDeviceWithoutLock() *voltha.LogicalDevice { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 220 | logger.Debug("getLogicalDeviceWithoutLock") |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 221 | return proto.Clone(agent.logicalDevice).(*voltha.LogicalDevice) |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 222 | } |
| 223 | |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 224 | //updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 225 | func (agent *LogicalAgent) updateLogicalDeviceWithoutLock(ctx context.Context, logicalDevice *voltha.LogicalDevice) error { |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 226 | if agent.stopped { |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame] | 227 | return fmt.Errorf("logical device agent stopped-%s", logicalDevice.Id) |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 228 | } |
| 229 | |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 230 | updateCtx := context.WithValue(ctx, model.RequestTimestamp, time.Now().UnixNano()) |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 231 | if err := agent.clusterDataProxy.Update(updateCtx, "logical_devices/"+agent.logicalDeviceID, logicalDevice); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 232 | logger.Errorw("failed-to-update-logical-devices-to-cluster-proxy", log.Fields{"error": err}) |
Thomas Lee S | e5a4401 | 2019-11-07 20:32:24 +0530 | [diff] [blame] | 233 | return err |
| 234 | } |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 235 | |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 236 | agent.logicalDevice = logicalDevice |
| 237 | |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 238 | return nil |
| 239 | } |
| 240 | |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame] | 241 | func (agent *LogicalAgent) deleteFlowAndUpdateMeterStats(ctx context.Context, mod *ofp.OfpFlowMod, chunk *FlowChunk) error { |
| 242 | chunk.lock.Lock() |
| 243 | defer chunk.lock.Unlock() |
| 244 | if changedMeter := agent.updateFlowCountOfMeterStats(ctx, mod, chunk.flow, false); !changedMeter { |
| 245 | return fmt.Errorf("Cannot-delete-flow-%s. Meter-update-failed", chunk.flow) |
| 246 | } |
| 247 | // Update store and cache |
| 248 | if err := agent.removeLogicalDeviceFlow(ctx, chunk.flow.Id); err != nil { |
| 249 | return fmt.Errorf("Cannot-delete-flows-%s. Delete-from-store-failed", chunk.flow) |
| 250 | } |
| 251 | return nil |
| 252 | } |
| 253 | |
khenaidoo | 0db4c81 | 2020-05-27 15:27:30 -0400 | [diff] [blame^] | 254 | func (agent *LogicalAgent) addFlowsAndGroupsToDevices(deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 255 | logger.Debugw("send-add-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID, "deviceRules": deviceRules, "flowMetadata": flowMetadata}) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 256 | |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 257 | responses := make([]coreutils.Response, 0) |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 258 | for deviceID, value := range deviceRules.GetRules() { |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 259 | response := coreutils.NewResponse() |
| 260 | responses = append(responses, response) |
| 261 | go func(deviceId string, value *fu.FlowsAndGroups) { |
khenaidoo | 0db4c81 | 2020-05-27 15:27:30 -0400 | [diff] [blame^] | 262 | subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout) |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 263 | defer cancel() |
khenaidoo | 0db4c81 | 2020-05-27 15:27:30 -0400 | [diff] [blame^] | 264 | start := time.Now() |
| 265 | if err := agent.deviceMgr.addFlowsAndGroups(subCtx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil { |
| 266 | logger.Errorw("flow-add-failed", log.Fields{"deviceID": deviceId, "error": err, "wait-time": time.Since(start)}) |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 267 | response.Error(status.Errorf(codes.Internal, "flow-add-failed: %s", deviceId)) |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 268 | } |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 269 | response.Done() |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 270 | }(deviceID, value) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 271 | } |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 272 | // Return responses (an array of channels) for the caller to wait for a response from the far end. |
| 273 | return responses |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 274 | } |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 275 | |
khenaidoo | 0db4c81 | 2020-05-27 15:27:30 -0400 | [diff] [blame^] | 276 | func (agent *LogicalAgent) deleteFlowsAndGroupsFromDevices(deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 277 | logger.Debugw("send-delete-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID}) |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 278 | |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 279 | responses := make([]coreutils.Response, 0) |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 280 | for deviceID, value := range deviceRules.GetRules() { |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 281 | response := coreutils.NewResponse() |
| 282 | responses = append(responses, response) |
| 283 | go func(deviceId string, value *fu.FlowsAndGroups) { |
khenaidoo | 0db4c81 | 2020-05-27 15:27:30 -0400 | [diff] [blame^] | 284 | subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout) |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 285 | defer cancel() |
khenaidoo | 0db4c81 | 2020-05-27 15:27:30 -0400 | [diff] [blame^] | 286 | start := time.Now() |
| 287 | if err := agent.deviceMgr.deleteFlowsAndGroups(subCtx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil { |
| 288 | logger.Errorw("flow-delete-failed", log.Fields{"deviceID": deviceId, "error": err, "wait-time": time.Since(start)}) |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 289 | response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s", deviceId)) |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 290 | } |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 291 | response.Done() |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 292 | }(deviceID, value) |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 293 | } |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 294 | return responses |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 295 | } |
| 296 | |
khenaidoo | 0db4c81 | 2020-05-27 15:27:30 -0400 | [diff] [blame^] | 297 | func (agent *LogicalAgent) updateFlowsAndGroupsOfDevice(deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 298 | logger.Debugw("send-update-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID}) |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 299 | |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 300 | responses := make([]coreutils.Response, 0) |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 301 | for deviceID, value := range deviceRules.GetRules() { |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 302 | response := coreutils.NewResponse() |
| 303 | responses = append(responses, response) |
| 304 | go func(deviceId string, value *fu.FlowsAndGroups) { |
khenaidoo | 0db4c81 | 2020-05-27 15:27:30 -0400 | [diff] [blame^] | 305 | subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout) |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 306 | defer cancel() |
khenaidoo | 0db4c81 | 2020-05-27 15:27:30 -0400 | [diff] [blame^] | 307 | if err := agent.deviceMgr.updateFlowsAndGroups(subCtx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil { |
khenaidoo | 787224a | 2020-04-16 18:08:47 -0400 | [diff] [blame] | 308 | logger.Errorw("flow-update-failed", log.Fields{"deviceID": deviceId, "error": err}) |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 309 | response.Error(status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId)) |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 310 | } |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 311 | response.Done() |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 312 | }(deviceID, value) |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 313 | } |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 314 | return responses |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 315 | } |
| 316 | |
khenaidoo | 0db4c81 | 2020-05-27 15:27:30 -0400 | [diff] [blame^] | 317 | func (agent *LogicalAgent) deleteFlowsFromParentDevice(flows ofp.Flows, metadata *voltha.FlowMetadata) []coreutils.Response { |
khenaidoo | 787224a | 2020-04-16 18:08:47 -0400 | [diff] [blame] | 318 | logger.Debugw("deleting-flows-from-parent-device", log.Fields{"logical-device-id": agent.logicalDeviceID, "flows": flows}) |
| 319 | responses := make([]coreutils.Response, 0) |
| 320 | for _, flow := range flows.Items { |
| 321 | response := coreutils.NewResponse() |
| 322 | responses = append(responses, response) |
| 323 | uniPort, err := agent.getUNILogicalPortNo(flow) |
| 324 | if err != nil { |
| 325 | logger.Error("no-uni-port-in-flow", log.Fields{"deviceID": agent.rootDeviceID, "flow": flow, "error": err}) |
| 326 | response.Error(err) |
| 327 | response.Done() |
| 328 | continue |
| 329 | } |
| 330 | logger.Debugw("uni-port", log.Fields{"flows": flows, "uni-port": uniPort}) |
| 331 | go func(uniPort uint32, metadata *voltha.FlowMetadata) { |
khenaidoo | 0db4c81 | 2020-05-27 15:27:30 -0400 | [diff] [blame^] | 332 | subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout) |
khenaidoo | 787224a | 2020-04-16 18:08:47 -0400 | [diff] [blame] | 333 | defer cancel() |
khenaidoo | 0db4c81 | 2020-05-27 15:27:30 -0400 | [diff] [blame^] | 334 | if err := agent.deviceMgr.deleteParentFlows(subCtx, agent.rootDeviceID, uniPort, metadata); err != nil { |
khenaidoo | 787224a | 2020-04-16 18:08:47 -0400 | [diff] [blame] | 335 | logger.Error("flow-delete-failed", log.Fields{"device-id": agent.rootDeviceID, "error": err}) |
| 336 | response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s %v", agent.rootDeviceID, err)) |
| 337 | } |
| 338 | response.Done() |
| 339 | }(uniPort, metadata) |
| 340 | } |
| 341 | return responses |
| 342 | } |
| 343 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 344 | func (agent *LogicalAgent) packetOut(ctx context.Context, packet *ofp.OfpPacketOut) { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 345 | logger.Debugw("packet-out", log.Fields{ |
Matteo Scandolo | 360605d | 2019-11-05 18:29:17 -0800 | [diff] [blame] | 346 | "packet": hex.EncodeToString(packet.Data), |
| 347 | "inPort": packet.GetInPort(), |
| 348 | }) |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 349 | outPort := fu.GetPacketOutPort(packet) |
khenaidoo | fdbad6e | 2018-11-06 22:26:38 -0500 | [diff] [blame] | 350 | //frame := packet.GetData() |
| 351 | //TODO: Use a channel between the logical agent and the device agent |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 352 | if err := agent.deviceMgr.packetOut(ctx, agent.rootDeviceID, outPort, packet); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 353 | logger.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceID}) |
khenaidoo | ca30132 | 2019-01-09 23:06:32 -0500 | [diff] [blame] | 354 | } |
khenaidoo | fdbad6e | 2018-11-06 22:26:38 -0500 | [diff] [blame] | 355 | } |
| 356 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 357 | func (agent *LogicalAgent) packetIn(port uint32, transactionID string, packet []byte) { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 358 | logger.Debugw("packet-in", log.Fields{ |
Matteo Scandolo | 360605d | 2019-11-05 18:29:17 -0800 | [diff] [blame] | 359 | "port": port, |
| 360 | "packet": hex.EncodeToString(packet), |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 361 | "transactionId": transactionID, |
Matteo Scandolo | 360605d | 2019-11-05 18:29:17 -0800 | [diff] [blame] | 362 | }) |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 363 | packetIn := fu.MkPacketIn(port, packet) |
Kent Hagerman | 45a13e4 | 2020-04-13 12:23:50 -0400 | [diff] [blame] | 364 | agent.ldeviceMgr.SendPacketIn(agent.logicalDeviceID, transactionID, packetIn) |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 365 | logger.Debugw("sending-packet-in", log.Fields{"packet": hex.EncodeToString(packetIn.Data)}) |
khenaidoo | fdbad6e | 2018-11-06 22:26:38 -0500 | [diff] [blame] | 366 | } |