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 | "errors" |
| 23 | "fmt" |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 24 | "strconv" |
David Bainbridge | d1afd66 | 2020-03-26 18:27:41 -0700 | [diff] [blame] | 25 | "sync" |
| 26 | "time" |
| 27 | |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 28 | "github.com/gogo/protobuf/proto" |
sbarbari | 17d7e22 | 2019-11-05 10:02:29 -0500 | [diff] [blame] | 29 | "github.com/opencord/voltha-go/db/model" |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 30 | fd "github.com/opencord/voltha-go/rw_core/flowdecomposition" |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 31 | "github.com/opencord/voltha-go/rw_core/route" |
Scott Baker | b671a86 | 2019-10-24 10:53:40 -0700 | [diff] [blame] | 32 | coreutils "github.com/opencord/voltha-go/rw_core/utils" |
serkant.uluderya | 2ae470f | 2020-01-21 11:13:09 -0800 | [diff] [blame] | 33 | fu "github.com/opencord/voltha-lib-go/v3/pkg/flows" |
| 34 | "github.com/opencord/voltha-lib-go/v3/pkg/log" |
| 35 | ic "github.com/opencord/voltha-protos/v3/go/inter_container" |
| 36 | ofp "github.com/opencord/voltha-protos/v3/go/openflow_13" |
| 37 | "github.com/opencord/voltha-protos/v3/go/voltha" |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 38 | "google.golang.org/grpc/codes" |
| 39 | "google.golang.org/grpc/status" |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 40 | ) |
| 41 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 42 | // LogicalAgent represent attributes of logical device agent |
| 43 | type LogicalAgent struct { |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 44 | logicalDeviceID string |
David Bainbridge | d1afd66 | 2020-03-26 18:27:41 -0700 | [diff] [blame] | 45 | serialNumber string |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 46 | rootDeviceID string |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 47 | deviceMgr *Manager |
| 48 | ldeviceMgr *LogicalManager |
khenaidoo | 3306c99 | 2019-05-24 16:57:35 -0400 | [diff] [blame] | 49 | clusterDataProxy *model.Proxy |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 50 | stopped bool |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 51 | deviceRoutes *route.DeviceRoutes |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 52 | lockDeviceRoutes sync.RWMutex |
khenaidoo | 3306c99 | 2019-05-24 16:57:35 -0400 | [diff] [blame] | 53 | logicalPortsNo map[uint32]bool //value is true for NNI port |
| 54 | lockLogicalPortsNo sync.RWMutex |
| 55 | flowDecomposer *fd.FlowDecomposer |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 56 | defaultTimeout time.Duration |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 57 | logicalDevice *voltha.LogicalDevice |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 58 | requestQueue *coreutils.RequestQueue |
| 59 | startOnce sync.Once |
| 60 | stopOnce sync.Once |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 61 | |
| 62 | meters map[uint32]*MeterChunk |
| 63 | meterLock sync.RWMutex |
| 64 | flows map[uint64]*FlowChunk |
| 65 | flowLock sync.RWMutex |
| 66 | groups map[uint32]*GroupChunk |
| 67 | groupLock sync.RWMutex |
| 68 | } |
| 69 | |
| 70 | //MeterChunk keeps a meter entry and its lock. The lock in the struct is used to syncronize the |
| 71 | //modifications for the related meter. |
| 72 | type MeterChunk struct { |
| 73 | meter *ofp.OfpMeterEntry |
| 74 | lock sync.Mutex |
| 75 | } |
| 76 | |
| 77 | //FlowChunk keeps a flow and the lock for this flow. The lock in the struct is used to syncronize the |
| 78 | //modifications for the related flow. |
| 79 | type FlowChunk struct { |
| 80 | flow *ofp.OfpFlowStats |
| 81 | lock sync.Mutex |
| 82 | } |
| 83 | |
| 84 | //GroupChunk keeps a group entry and its lock. The lock in the struct is used to syncronize the |
| 85 | //modifications for the related group. |
| 86 | type GroupChunk struct { |
| 87 | group *ofp.OfpGroupEntry |
| 88 | lock sync.Mutex |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 89 | } |
| 90 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 91 | func newLogicalDeviceAgent(id string, sn string, deviceID string, ldeviceMgr *LogicalManager, |
| 92 | deviceMgr *Manager, cdProxy *model.Proxy, timeout time.Duration) *LogicalAgent { |
| 93 | var agent LogicalAgent |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 94 | agent.logicalDeviceID = id |
David Bainbridge | d1afd66 | 2020-03-26 18:27:41 -0700 | [diff] [blame] | 95 | agent.serialNumber = sn |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 96 | agent.rootDeviceID = deviceID |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 97 | agent.deviceMgr = deviceMgr |
khenaidoo | 9a46896 | 2018-09-19 15:33:13 -0400 | [diff] [blame] | 98 | agent.clusterDataProxy = cdProxy |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 99 | agent.ldeviceMgr = ldeviceMgr |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 100 | agent.flowDecomposer = fd.NewFlowDecomposer(agent.deviceMgr) |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 101 | agent.logicalPortsNo = make(map[uint32]bool) |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 102 | agent.defaultTimeout = timeout |
Kent Hagerman | 730cbdf | 2020-03-31 12:22:08 -0400 | [diff] [blame] | 103 | agent.requestQueue = coreutils.NewRequestQueue() |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 104 | agent.meters = make(map[uint32]*MeterChunk) |
| 105 | agent.flows = make(map[uint64]*FlowChunk) |
| 106 | agent.groups = make(map[uint32]*GroupChunk) |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 107 | return &agent |
| 108 | } |
| 109 | |
khenaidoo | 4d4802d | 2018-10-04 21:59:49 -0400 | [diff] [blame] | 110 | // start creates the logical device and add it to the data model |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 111 | func (agent *LogicalAgent) start(ctx context.Context, loadFromDB bool) error { |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 112 | needToStart := false |
| 113 | if agent.startOnce.Do(func() { needToStart = true }); !needToStart { |
| 114 | return nil |
| 115 | } |
| 116 | |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 117 | 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] | 118 | |
| 119 | var startSucceeded bool |
| 120 | defer func() { |
| 121 | if !startSucceeded { |
| 122 | if err := agent.stop(ctx); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 123 | 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] | 124 | } |
| 125 | } |
| 126 | }() |
| 127 | |
khenaidoo | 297cd25 | 2019-02-07 22:10:23 -0500 | [diff] [blame] | 128 | var ld *voltha.LogicalDevice |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 129 | if !loadFromDB { |
khenaidoo | 7e3d8f1 | 2019-08-02 16:06:30 -0400 | [diff] [blame] | 130 | //Build the logical device based on information retrieved from the device adapter |
| 131 | var switchCap *ic.SwitchCapability |
khenaidoo | 297cd25 | 2019-02-07 22:10:23 -0500 | [diff] [blame] | 132 | var err error |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 133 | if switchCap, err = agent.deviceMgr.getSwitchCapability(ctx, agent.rootDeviceID); err != nil { |
khenaidoo | 7e3d8f1 | 2019-08-02 16:06:30 -0400 | [diff] [blame] | 134 | return err |
| 135 | } |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 136 | ld = &voltha.LogicalDevice{Id: agent.logicalDeviceID, RootDeviceId: agent.rootDeviceID} |
khenaidoo | 297cd25 | 2019-02-07 22:10:23 -0500 | [diff] [blame] | 137 | |
| 138 | // Create the datapath ID (uint64) using the logical device ID (based on the MAC Address) |
| 139 | var datapathID uint64 |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 140 | if datapathID, err = coreutils.CreateDataPathID(agent.serialNumber); err != nil { |
khenaidoo | 297cd25 | 2019-02-07 22:10:23 -0500 | [diff] [blame] | 141 | return err |
| 142 | } |
| 143 | ld.DatapathId = datapathID |
khenaidoo | 7e3d8f1 | 2019-08-02 16:06:30 -0400 | [diff] [blame] | 144 | ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc) |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 145 | logger.Debugw("Switch-capability", log.Fields{"Desc": ld.Desc, "fromAd": switchCap.Desc}) |
khenaidoo | 7e3d8f1 | 2019-08-02 16:06:30 -0400 | [diff] [blame] | 146 | ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures) |
khenaidoo | 297cd25 | 2019-02-07 22:10:23 -0500 | [diff] [blame] | 147 | ld.Flows = &ofp.Flows{Items: nil} |
| 148 | ld.FlowGroups = &ofp.FlowGroups{Items: nil} |
khenaidoo | 4908535 | 2020-01-13 19:15:43 -0500 | [diff] [blame] | 149 | ld.Ports = []*voltha.LogicalPort{} |
khenaidoo | 297cd25 | 2019-02-07 22:10:23 -0500 | [diff] [blame] | 150 | |
khenaidoo | 297cd25 | 2019-02-07 22:10:23 -0500 | [diff] [blame] | 151 | // Save the logical device |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 152 | if err := agent.clusterDataProxy.AddWithID(ctx, "logical_devices", ld.Id, ld); err != nil { |
| 153 | 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] | 154 | return err |
| 155 | } |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 156 | 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] | 157 | |
| 158 | agent.logicalDevice = proto.Clone(ld).(*voltha.LogicalDevice) |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 159 | |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 160 | // Setup the logicalports - internal processing, no need to propagate the client context |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 161 | go func() { |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 162 | err := agent.setupLogicalPorts(context.Background()) |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 163 | if err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 164 | logger.Errorw("unable-to-setup-logical-ports", log.Fields{"error": err}) |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 165 | } |
| 166 | }() |
khenaidoo | 297cd25 | 2019-02-07 22:10:23 -0500 | [diff] [blame] | 167 | } else { |
| 168 | // load from dB - the logical may not exist at this time. On error, just return and the calling function |
| 169 | // will destroy this agent. |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 170 | ld := &voltha.LogicalDevice{} |
| 171 | have, err := agent.clusterDataProxy.Get(ctx, "logical_devices/"+agent.logicalDeviceID, ld) |
Thomas Lee S | e5a4401 | 2019-11-07 20:32:24 +0530 | [diff] [blame] | 172 | if err != nil { |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 173 | return err |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 174 | } else if !have { |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 175 | return status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceID) |
khenaidoo | 297cd25 | 2019-02-07 22:10:23 -0500 | [diff] [blame] | 176 | } |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 177 | |
khenaidoo | 8c3303d | 2019-02-13 14:59:39 -0500 | [diff] [blame] | 178 | // Update the root device Id |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 179 | agent.rootDeviceID = ld.RootDeviceId |
khenaidoo | 3d3b8c2 | 2019-05-22 18:10:39 -0400 | [diff] [blame] | 180 | |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 181 | // Update the last data |
| 182 | agent.logicalDevice = proto.Clone(ld).(*voltha.LogicalDevice) |
| 183 | |
khenaidoo | 3d3b8c2 | 2019-05-22 18:10:39 -0400 | [diff] [blame] | 184 | // Setup the local list of logical ports |
| 185 | agent.addLogicalPortsToMap(ld.Ports) |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 186 | // load the flows, meters and groups from KV to cache |
| 187 | agent.loadFlows(ctx) |
| 188 | agent.loadMeters(ctx) |
| 189 | agent.loadGroups(ctx) |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 190 | } |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 191 | |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 192 | // 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] | 193 | if loadFromDB { |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 194 | go func() { |
| 195 | if err := agent.buildRoutes(context.Background()); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 196 | 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] | 197 | } |
| 198 | }() |
khenaidoo | 4c9e559 | 2019-09-09 16:20:41 -0400 | [diff] [blame] | 199 | } |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 200 | startSucceeded = true |
| 201 | |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 202 | return nil |
| 203 | } |
| 204 | |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 205 | // 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] | 206 | func (agent *LogicalAgent) stop(ctx context.Context) error { |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 207 | var returnErr error |
| 208 | agent.stopOnce.Do(func() { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 209 | logger.Info("stopping-logical_device-agent") |
khenaidoo | 8c3303d | 2019-02-13 14:59:39 -0500 | [diff] [blame] | 210 | |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 211 | if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil { |
| 212 | // This should never happen - an error is returned only if the agent is stopped and an agent is only stopped once. |
| 213 | returnErr = err |
| 214 | return |
| 215 | } |
| 216 | defer agent.requestQueue.RequestComplete() |
| 217 | |
| 218 | //Remove the logical device from the model |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 219 | if err := agent.clusterDataProxy.Remove(ctx, "logical_devices/"+agent.logicalDeviceID); err != nil { |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 220 | returnErr = err |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 221 | } else { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 222 | logger.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceID}) |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 223 | } |
| 224 | |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 225 | agent.stopped = true |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 226 | |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 227 | logger.Info("logical_device-agent-stopped") |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 228 | }) |
| 229 | return returnErr |
khenaidoo | 4d4802d | 2018-10-04 21:59:49 -0400 | [diff] [blame] | 230 | } |
| 231 | |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 232 | // GetLogicalDevice returns the latest logical device data |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 233 | func (agent *LogicalAgent) GetLogicalDevice(ctx context.Context) (*voltha.LogicalDevice, error) { |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 234 | if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil { |
| 235 | return nil, err |
| 236 | } |
| 237 | defer agent.requestQueue.RequestComplete() |
| 238 | return proto.Clone(agent.logicalDevice).(*voltha.LogicalDevice), nil |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 239 | } |
| 240 | |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 241 | // ListLogicalDeviceFlows returns logical device flows |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 242 | func (agent *LogicalAgent) ListLogicalDeviceFlows(ctx context.Context) (*ofp.Flows, error) { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 243 | logger.Debug("ListLogicalDeviceFlows") |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 244 | var flowStats []*ofp.OfpFlowStats |
| 245 | agent.flowLock.RLock() |
| 246 | defer agent.flowLock.RUnlock() |
| 247 | for _, flowChunk := range agent.flows { |
| 248 | flowStats = append(flowStats, (proto.Clone(flowChunk.flow)).(*ofp.OfpFlowStats)) |
khenaidoo | dd23717 | 2019-05-27 16:37:17 -0400 | [diff] [blame] | 249 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 250 | return &ofp.Flows{Items: flowStats}, nil |
khenaidoo | dd23717 | 2019-05-27 16:37:17 -0400 | [diff] [blame] | 251 | } |
| 252 | |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 253 | // ListLogicalDeviceMeters returns logical device meters |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 254 | func (agent *LogicalAgent) ListLogicalDeviceMeters(ctx context.Context) (*ofp.Meters, error) { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 255 | logger.Debug("ListLogicalDeviceMeters") |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 256 | |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 257 | var meterEntries []*ofp.OfpMeterEntry |
| 258 | agent.meterLock.RLock() |
| 259 | defer agent.meterLock.RUnlock() |
| 260 | for _, meterChunk := range agent.meters { |
| 261 | meterEntries = append(meterEntries, (proto.Clone(meterChunk.meter)).(*ofp.OfpMeterEntry)) |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 262 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 263 | return &ofp.Meters{Items: meterEntries}, nil |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 264 | } |
| 265 | |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 266 | // ListLogicalDeviceFlowGroups returns logical device flow groups |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 267 | func (agent *LogicalAgent) ListLogicalDeviceFlowGroups(ctx context.Context) (*ofp.FlowGroups, error) { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 268 | logger.Debug("ListLogicalDeviceFlowGroups") |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 269 | |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 270 | var groupEntries []*ofp.OfpGroupEntry |
| 271 | agent.groupLock.RLock() |
| 272 | defer agent.groupLock.RUnlock() |
| 273 | for _, value := range agent.groups { |
| 274 | groupEntries = append(groupEntries, (proto.Clone(value.group)).(*ofp.OfpGroupEntry)) |
khenaidoo | dd23717 | 2019-05-27 16:37:17 -0400 | [diff] [blame] | 275 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 276 | return &ofp.FlowGroups{Items: groupEntries}, nil |
khenaidoo | dd23717 | 2019-05-27 16:37:17 -0400 | [diff] [blame] | 277 | } |
| 278 | |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 279 | // ListLogicalDevicePorts returns logical device ports |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 280 | func (agent *LogicalAgent) ListLogicalDevicePorts(ctx context.Context) (*voltha.LogicalPorts, error) { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 281 | logger.Debug("ListLogicalDevicePorts") |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 282 | logicalDevice, err := agent.GetLogicalDevice(ctx) |
| 283 | if err != nil { |
| 284 | return nil, err |
| 285 | } |
| 286 | if logicalDevice == nil { |
| 287 | return &voltha.LogicalPorts{}, nil |
| 288 | } |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 289 | lPorts := make([]*voltha.LogicalPort, 0) |
| 290 | lPorts = append(lPorts, logicalDevice.Ports...) |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 291 | return &voltha.LogicalPorts{Items: lPorts}, nil |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 292 | } |
| 293 | |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 294 | //updateLogicalDeviceFlow updates flow in the store and cache |
| 295 | //It is assumed that the chunk lock has been acquired before this function is called |
| 296 | func (agent *LogicalAgent) updateLogicalDeviceFlow(ctx context.Context, flow *ofp.OfpFlowStats, flowChunk *FlowChunk) error { |
| 297 | path := fmt.Sprintf("logical_flows/%s/%d", agent.logicalDeviceID, flow.Id) |
| 298 | if err := agent.clusterDataProxy.Update(ctx, path, flow); err != nil { |
| 299 | return status.Errorf(codes.Internal, "failed-update-flow:%s:%d %s", agent.logicalDeviceID, flow.Id, err) |
khenaidoo | 43c8212 | 2018-11-22 18:38:28 -0500 | [diff] [blame] | 300 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 301 | flowChunk.flow = flow |
khenaidoo | 43c8212 | 2018-11-22 18:38:28 -0500 | [diff] [blame] | 302 | return nil |
| 303 | } |
| 304 | |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 305 | //removeLogicalDeviceFlow deletes the flow from store and cache. |
| 306 | //It is assumed that the chunk lock has been acquired before this function is called |
| 307 | func (agent *LogicalAgent) removeLogicalDeviceFlow(ctx context.Context, flowID uint64) error { |
| 308 | path := fmt.Sprintf("logical_flows/%s/%d", agent.logicalDeviceID, flowID) |
| 309 | if err := agent.clusterDataProxy.Remove(ctx, path); err != nil { |
| 310 | return fmt.Errorf("couldnt-delete-flow-from-the-store-%s", path) |
| 311 | } |
| 312 | agent.flowLock.Lock() |
| 313 | defer agent.flowLock.Unlock() |
| 314 | delete(agent.flows, flowID) |
| 315 | return nil |
| 316 | } |
khenaidoo | 4c9e559 | 2019-09-09 16:20:41 -0400 | [diff] [blame] | 317 | |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 318 | //updateLogicalDeviceMeter updates meter info in store and cache |
| 319 | //It is assumed that the chunk lock has been acquired before this function is called |
| 320 | func (agent *LogicalAgent) updateLogicalDeviceMeter(ctx context.Context, meter *ofp.OfpMeterEntry, meterChunk *MeterChunk) error { |
| 321 | path := fmt.Sprintf("meters/%s/%d", agent.logicalDeviceID, meter.Config.MeterId) |
| 322 | if err := agent.clusterDataProxy.Update(ctx, path, meter); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 323 | logger.Errorw("error-updating-logical-device-with-meters", log.Fields{"error": err}) |
khenaidoo | 4c9e559 | 2019-09-09 16:20:41 -0400 | [diff] [blame] | 324 | return err |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 325 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 326 | meterChunk.meter = meter |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 327 | return nil |
| 328 | } |
| 329 | |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 330 | //removeLogicalDeviceMeter deletes the meter from store and cache |
| 331 | //It is assumed that the chunk lock has been acquired before this function is called |
| 332 | func (agent *LogicalAgent) removeLogicalDeviceMeter(ctx context.Context, meterID uint32) error { |
| 333 | path := fmt.Sprintf("meters/%s/%d", agent.logicalDeviceID, meterID) |
| 334 | if err := agent.clusterDataProxy.Remove(ctx, path); err != nil { |
| 335 | return fmt.Errorf("couldnt-delete-meter-from-store-%s", path) |
| 336 | } |
| 337 | agent.meterLock.Lock() |
| 338 | defer agent.meterLock.Unlock() |
| 339 | delete(agent.meters, meterID) |
| 340 | return nil |
| 341 | } |
khenaidoo | 4c9e559 | 2019-09-09 16:20:41 -0400 | [diff] [blame] | 342 | |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 343 | //updateLogicalDeviceFlowGroup updates the flow groups in store and cache |
| 344 | //It is assumed that the chunk lock has been acquired before this function is called |
| 345 | func (agent *LogicalAgent) updateLogicalDeviceFlowGroup(ctx context.Context, groupEntry *ofp.OfpGroupEntry, groupChunk *GroupChunk) error { |
| 346 | path := fmt.Sprintf("groups/%s/%d", agent.logicalDeviceID, groupEntry.Desc.GroupId) |
| 347 | if err := agent.clusterDataProxy.Update(ctx, path, groupEntry); err != nil { |
| 348 | logger.Errorw("error-updating-logical-device-with-group", log.Fields{"error": err}) |
khenaidoo | 4c9e559 | 2019-09-09 16:20:41 -0400 | [diff] [blame] | 349 | return err |
khenaidoo | 43c8212 | 2018-11-22 18:38:28 -0500 | [diff] [blame] | 350 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 351 | groupChunk.group = groupEntry |
| 352 | return nil |
| 353 | } |
| 354 | |
| 355 | //removeLogicalDeviceFlowGroup removes the flow groups in store and cache |
| 356 | //It is assumed that the chunk lock has been acquired before this function is called |
| 357 | func (agent *LogicalAgent) removeLogicalDeviceFlowGroup(ctx context.Context, groupID uint32) error { |
| 358 | path := fmt.Sprintf("groups/%s/%d", agent.logicalDeviceID, groupID) |
| 359 | if err := agent.clusterDataProxy.Remove(ctx, path); err != nil { |
| 360 | return fmt.Errorf("couldnt-delete-group-from-store-%s", path) |
| 361 | } |
| 362 | agent.groupLock.Lock() |
| 363 | defer agent.groupLock.Unlock() |
| 364 | delete(agent.groups, groupID) |
khenaidoo | 43c8212 | 2018-11-22 18:38:28 -0500 | [diff] [blame] | 365 | return nil |
| 366 | } |
| 367 | |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 368 | // 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] | 369 | func (agent *LogicalAgent) getLogicalDeviceWithoutLock() *voltha.LogicalDevice { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 370 | logger.Debug("getLogicalDeviceWithoutLock") |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 371 | return proto.Clone(agent.logicalDevice).(*voltha.LogicalDevice) |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 372 | } |
| 373 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 374 | func (agent *LogicalAgent) updateLogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) error { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 375 | logger.Debugw("updateLogicalPort", log.Fields{"deviceId": device.Id, "port": port}) |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 376 | var err error |
| 377 | if port.Type == voltha.Port_ETHERNET_NNI { |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 378 | if _, err = agent.addNNILogicalPort(ctx, device, port); err != nil { |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 379 | return err |
| 380 | } |
| 381 | agent.addLogicalPortToMap(port.PortNo, true) |
| 382 | } else if port.Type == voltha.Port_ETHERNET_UNI { |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 383 | if _, err = agent.addUNILogicalPort(ctx, device, port); err != nil { |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 384 | return err |
| 385 | } |
| 386 | agent.addLogicalPortToMap(port.PortNo, false) |
| 387 | } else { |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 388 | // Update the device routes to ensure all routes on the logical device have been calculated |
| 389 | if err = agent.buildRoutes(ctx); err != nil { |
| 390 | // Not an error - temporary state |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 391 | logger.Warnw("failed-to-update-routes", log.Fields{"device-id": device.Id, "port": port, "error": err}) |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 392 | } |
| 393 | } |
| 394 | return nil |
| 395 | } |
| 396 | |
khenaidoo | 3d3b8c2 | 2019-05-22 18:10:39 -0400 | [diff] [blame] | 397 | // setupLogicalPorts is invoked once the logical device has been created and is ready to get ports |
| 398 | // added to it. While the logical device was being created we could have received requests to add |
| 399 | // NNI and UNI ports which were discarded. Now is the time to add them if needed |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 400 | func (agent *LogicalAgent) setupLogicalPorts(ctx context.Context) error { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 401 | logger.Infow("setupLogicalPorts", log.Fields{"logicalDeviceId": agent.logicalDeviceID}) |
khenaidoo | 3d3b8c2 | 2019-05-22 18:10:39 -0400 | [diff] [blame] | 402 | // First add any NNI ports which could have been missing |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 403 | if err := agent.setupNNILogicalPorts(ctx, agent.rootDeviceID); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 404 | logger.Errorw("error-setting-up-NNI-ports", log.Fields{"error": err, "deviceId": agent.rootDeviceID}) |
khenaidoo | 3d3b8c2 | 2019-05-22 18:10:39 -0400 | [diff] [blame] | 405 | return err |
| 406 | } |
| 407 | |
| 408 | // Now, set up the UNI ports if needed. |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 409 | children, err := agent.deviceMgr.GetAllChildDevices(ctx, agent.rootDeviceID) |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 410 | if err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 411 | logger.Errorw("error-getting-child-devices", log.Fields{"error": err, "deviceId": agent.rootDeviceID}) |
khenaidoo | 3d3b8c2 | 2019-05-22 18:10:39 -0400 | [diff] [blame] | 412 | return err |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 413 | } |
| 414 | responses := make([]coreutils.Response, 0) |
| 415 | for _, child := range children.Items { |
| 416 | response := coreutils.NewResponse() |
| 417 | responses = append(responses, response) |
| 418 | go func(child *voltha.Device) { |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 419 | if err = agent.setupUNILogicalPorts(context.Background(), child); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 420 | logger.Error("setting-up-UNI-ports-failed", log.Fields{"deviceID": child.Id}) |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 421 | response.Error(status.Errorf(codes.Internal, "UNI-ports-setup-failed: %s", child.Id)) |
| 422 | } |
| 423 | response.Done() |
| 424 | }(child) |
| 425 | } |
| 426 | // Wait for completion |
| 427 | if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, responses...); res != nil { |
| 428 | return status.Errorf(codes.Aborted, "errors-%s", res) |
khenaidoo | 3d3b8c2 | 2019-05-22 18:10:39 -0400 | [diff] [blame] | 429 | } |
| 430 | return nil |
| 431 | } |
| 432 | |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 433 | // setupNNILogicalPorts creates an NNI port on the logical device that represents an NNI interface on a root device |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 434 | func (agent *LogicalAgent) setupNNILogicalPorts(ctx context.Context, deviceID string) error { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 435 | logger.Infow("setupNNILogicalPorts-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID}) |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 436 | // Build the logical device based on information retrieved from the device adapter |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 437 | var err error |
| 438 | |
| 439 | var device *voltha.Device |
Kent Hagerman | 45a13e4 | 2020-04-13 12:23:50 -0400 | [diff] [blame] | 440 | if device, err = agent.deviceMgr.getDevice(ctx, deviceID); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 441 | logger.Errorw("error-retrieving-device", log.Fields{"error": err, "deviceId": deviceID}) |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 442 | return err |
| 443 | } |
| 444 | |
| 445 | //Get UNI port number |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 446 | for _, port := range device.Ports { |
| 447 | if port.Type == voltha.Port_ETHERNET_NNI { |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 448 | if _, err = agent.addNNILogicalPort(ctx, device, port); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 449 | logger.Errorw("error-adding-UNI-port", log.Fields{"error": err}) |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 450 | } |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 451 | agent.addLogicalPortToMap(port.PortNo, true) |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 452 | } |
| 453 | } |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 454 | return err |
| 455 | } |
| 456 | |
khenaidoo | 171b98e | 2019-10-31 11:48:15 -0400 | [diff] [blame] | 457 | // updatePortState updates the port state of the device |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 458 | func (agent *LogicalAgent) updatePortState(ctx context.Context, deviceID string, portNo uint32, operStatus voltha.OperStatus_Types) error { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 459 | logger.Infow("updatePortState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "portNo": portNo, "state": operStatus}) |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 460 | if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil { |
| 461 | return err |
| 462 | } |
| 463 | defer agent.requestQueue.RequestComplete() |
khenaidoo | 171b98e | 2019-10-31 11:48:15 -0400 | [diff] [blame] | 464 | // Get the latest logical device info |
Kent Hagerman | d9cc2e9 | 2019-11-04 13:28:15 -0500 | [diff] [blame] | 465 | original := agent.getLogicalDeviceWithoutLock() |
| 466 | updatedPorts := clonePorts(original.Ports) |
| 467 | for _, port := range updatedPorts { |
| 468 | if port.DeviceId == deviceID && port.DevicePortNo == portNo { |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 469 | if operStatus == voltha.OperStatus_ACTIVE { |
Kent Hagerman | d9cc2e9 | 2019-11-04 13:28:15 -0500 | [diff] [blame] | 470 | port.OfpPort.Config = port.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN) |
| 471 | port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE) |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 472 | } else { |
Kent Hagerman | d9cc2e9 | 2019-11-04 13:28:15 -0500 | [diff] [blame] | 473 | port.OfpPort.Config = port.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN) |
| 474 | port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN) |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 475 | } |
| 476 | // Update the logical device |
Kent Hagerman | d9cc2e9 | 2019-11-04 13:28:15 -0500 | [diff] [blame] | 477 | if err := agent.updateLogicalDevicePortsWithoutLock(ctx, original, updatedPorts); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 478 | logger.Errorw("error-updating-logical-device", log.Fields{"error": err}) |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 479 | return err |
| 480 | } |
| 481 | return nil |
| 482 | } |
| 483 | } |
| 484 | return status.Errorf(codes.NotFound, "port-%d-not-exist", portNo) |
khenaidoo | 171b98e | 2019-10-31 11:48:15 -0400 | [diff] [blame] | 485 | } |
| 486 | |
khenaidoo | 3ab3488 | 2019-05-02 21:33:30 -0400 | [diff] [blame] | 487 | // updatePortsState updates the ports state related to the device |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 488 | func (agent *LogicalAgent) updatePortsState(ctx context.Context, device *voltha.Device, state voltha.OperStatus_Types) error { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 489 | logger.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID}) |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 490 | if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil { |
| 491 | return err |
| 492 | } |
| 493 | defer agent.requestQueue.RequestComplete() |
khenaidoo | 3ab3488 | 2019-05-02 21:33:30 -0400 | [diff] [blame] | 494 | // Get the latest logical device info |
Kent Hagerman | d9cc2e9 | 2019-11-04 13:28:15 -0500 | [diff] [blame] | 495 | original := agent.getLogicalDeviceWithoutLock() |
| 496 | updatedPorts := clonePorts(original.Ports) |
| 497 | for _, port := range updatedPorts { |
| 498 | if port.DeviceId == device.Id { |
kesavand | bc2d162 | 2020-01-21 00:42:01 -0500 | [diff] [blame] | 499 | if state == voltha.OperStatus_ACTIVE { |
Kent Hagerman | d9cc2e9 | 2019-11-04 13:28:15 -0500 | [diff] [blame] | 500 | port.OfpPort.Config = port.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN) |
| 501 | port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE) |
kesavand | bc2d162 | 2020-01-21 00:42:01 -0500 | [diff] [blame] | 502 | } else { |
Kent Hagerman | d9cc2e9 | 2019-11-04 13:28:15 -0500 | [diff] [blame] | 503 | port.OfpPort.Config = port.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN) |
| 504 | port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN) |
khenaidoo | 3ab3488 | 2019-05-02 21:33:30 -0400 | [diff] [blame] | 505 | } |
| 506 | } |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 507 | } |
| 508 | // Updating the logical device will trigger the poprt change events to be populated to the controller |
Kent Hagerman | d9cc2e9 | 2019-11-04 13:28:15 -0500 | [diff] [blame] | 509 | if err := agent.updateLogicalDevicePortsWithoutLock(ctx, original, updatedPorts); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 510 | logger.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceID, "error": err}) |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 511 | return err |
khenaidoo | 3ab3488 | 2019-05-02 21:33:30 -0400 | [diff] [blame] | 512 | } |
| 513 | return nil |
| 514 | } |
| 515 | |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 516 | // setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 517 | func (agent *LogicalAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device) error { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 518 | logger.Infow("setupUNILogicalPort", log.Fields{"logicalDeviceId": agent.logicalDeviceID}) |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 519 | // Build the logical device based on information retrieved from the device adapter |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 520 | var err error |
khenaidoo | 59ef7be | 2019-06-21 12:40:28 -0400 | [diff] [blame] | 521 | var added bool |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 522 | //Get UNI port number |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 523 | for _, port := range childDevice.Ports { |
| 524 | if port.Type == voltha.Port_ETHERNET_UNI { |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 525 | if added, err = agent.addUNILogicalPort(ctx, childDevice, port); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 526 | logger.Errorw("error-adding-UNI-port", log.Fields{"error": err}) |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 527 | } |
khenaidoo | 59ef7be | 2019-06-21 12:40:28 -0400 | [diff] [blame] | 528 | if added { |
| 529 | agent.addLogicalPortToMap(port.PortNo, false) |
| 530 | } |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 531 | } |
| 532 | } |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 533 | return err |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 534 | } |
| 535 | |
Girish Gowdra | 408cd96 | 2020-03-11 14:31:31 -0700 | [diff] [blame] | 536 | // deleteAllLogicalPorts deletes all logical ports associated with this logical device |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 537 | func (agent *LogicalAgent) deleteAllLogicalPorts(ctx context.Context) error { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 538 | logger.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID}) |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 539 | if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil { |
| 540 | return err |
| 541 | } |
| 542 | defer agent.requestQueue.RequestComplete() |
khenaidoo | 0a822f9 | 2019-05-08 15:15:57 -0400 | [diff] [blame] | 543 | // Get the latest logical device info |
Kent Hagerman | d9cc2e9 | 2019-11-04 13:28:15 -0500 | [diff] [blame] | 544 | cloned := agent.getLogicalDeviceWithoutLock() |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 545 | |
Kent Hagerman | d9cc2e9 | 2019-11-04 13:28:15 -0500 | [diff] [blame] | 546 | if err := agent.updateLogicalDevicePortsWithoutLock(ctx, cloned, []*voltha.LogicalPort{}); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 547 | logger.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceID, "error": err}) |
Girish Gowdra | 408cd96 | 2020-03-11 14:31:31 -0700 | [diff] [blame] | 548 | return err |
khenaidoo | 0a822f9 | 2019-05-08 15:15:57 -0400 | [diff] [blame] | 549 | } |
| 550 | return nil |
| 551 | } |
| 552 | |
Kent Hagerman | d9cc2e9 | 2019-11-04 13:28:15 -0500 | [diff] [blame] | 553 | func clonePorts(ports []*voltha.LogicalPort) []*voltha.LogicalPort { |
| 554 | return proto.Clone(&voltha.LogicalPorts{Items: ports}).(*voltha.LogicalPorts).Items |
| 555 | } |
| 556 | |
| 557 | //updateLogicalDevicePortsWithoutLock updates the |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 558 | func (agent *LogicalAgent) updateLogicalDevicePortsWithoutLock(ctx context.Context, device *voltha.LogicalDevice, newPorts []*voltha.LogicalPort) error { |
Kent Hagerman | d9cc2e9 | 2019-11-04 13:28:15 -0500 | [diff] [blame] | 559 | oldPorts := device.Ports |
| 560 | device.Ports = newPorts |
| 561 | if err := agent.updateLogicalDeviceWithoutLock(ctx, device); err != nil { |
| 562 | return err |
| 563 | } |
| 564 | agent.portUpdated(oldPorts, newPorts) |
| 565 | return nil |
| 566 | } |
| 567 | |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 568 | //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] | 569 | func (agent *LogicalAgent) updateLogicalDeviceWithoutLock(ctx context.Context, logicalDevice *voltha.LogicalDevice) error { |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 570 | if agent.stopped { |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 571 | return fmt.Errorf("logical device agent stopped-%s", logicalDevice.Id) |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 572 | } |
| 573 | |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 574 | updateCtx := context.WithValue(ctx, model.RequestTimestamp, time.Now().UnixNano()) |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 575 | 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] | 576 | 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] | 577 | return err |
| 578 | } |
Kent Hagerman | 4f355f5 | 2020-03-30 16:01:33 -0400 | [diff] [blame] | 579 | |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 580 | agent.logicalDevice = logicalDevice |
| 581 | |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 582 | return nil |
| 583 | } |
| 584 | |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 585 | //generateDeviceRoutesIfNeeded generates the device routes if the logical device has been updated since the last time |
khenaidoo | 4c9e559 | 2019-09-09 16:20:41 -0400 | [diff] [blame] | 586 | //that device graph was generated. |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 587 | func (agent *LogicalAgent) generateDeviceRoutesIfNeeded(ctx context.Context) error { |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 588 | agent.lockDeviceRoutes.Lock() |
| 589 | defer agent.lockDeviceRoutes.Unlock() |
| 590 | |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 591 | ld, err := agent.GetLogicalDevice(ctx) |
| 592 | if err != nil { |
| 593 | return err |
| 594 | } |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 595 | |
| 596 | if agent.deviceRoutes != nil && agent.deviceRoutes.IsUpToDate(ld) { |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 597 | return nil |
| 598 | } |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 599 | logger.Debug("Generation of device route required") |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 600 | if err := agent.buildRoutes(ctx); err != nil { |
khenaidoo | 787224a | 2020-04-16 18:08:47 -0400 | [diff] [blame] | 601 | // No Route is not an error |
| 602 | if !errors.Is(err, route.ErrNoRoute) { |
| 603 | return err |
| 604 | } |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 605 | } |
khenaidoo | 4c9e559 | 2019-09-09 16:20:41 -0400 | [diff] [blame] | 606 | return nil |
| 607 | } |
| 608 | |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 609 | //updateFlowTable updates the flow table of that logical device |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 610 | func (agent *LogicalAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error { |
| 611 | logger.Debug("UpdateFlowTable") |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 612 | if flow == nil { |
| 613 | return nil |
| 614 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 615 | |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 616 | if err := agent.generateDeviceRoutesIfNeeded(ctx); err != nil { |
khenaidoo | 4c9e559 | 2019-09-09 16:20:41 -0400 | [diff] [blame] | 617 | return err |
| 618 | } |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 619 | switch flow.GetCommand() { |
| 620 | case ofp.OfpFlowModCommand_OFPFC_ADD: |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 621 | return agent.flowAdd(ctx, flow) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 622 | case ofp.OfpFlowModCommand_OFPFC_DELETE: |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 623 | return agent.flowDelete(ctx, flow) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 624 | case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT: |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 625 | return agent.flowDeleteStrict(ctx, flow) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 626 | case ofp.OfpFlowModCommand_OFPFC_MODIFY: |
| 627 | return agent.flowModify(flow) |
| 628 | case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT: |
| 629 | return agent.flowModifyStrict(flow) |
| 630 | } |
| 631 | return status.Errorf(codes.Internal, |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 632 | "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, flow.GetCommand()) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 633 | } |
| 634 | |
| 635 | //updateGroupTable updates the group table of that logical device |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 636 | func (agent *LogicalAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 637 | logger.Debug("updateGroupTable") |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 638 | if groupMod == nil { |
| 639 | return nil |
| 640 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 641 | |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 642 | if err := agent.generateDeviceRoutesIfNeeded(ctx); err != nil { |
khenaidoo | 4c9e559 | 2019-09-09 16:20:41 -0400 | [diff] [blame] | 643 | return err |
| 644 | } |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 645 | |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 646 | switch groupMod.GetCommand() { |
| 647 | case ofp.OfpGroupModCommand_OFPGC_ADD: |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 648 | return agent.groupAdd(ctx, groupMod) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 649 | case ofp.OfpGroupModCommand_OFPGC_DELETE: |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 650 | return agent.groupDelete(ctx, groupMod) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 651 | case ofp.OfpGroupModCommand_OFPGC_MODIFY: |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 652 | return agent.groupModify(ctx, groupMod) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 653 | } |
| 654 | return status.Errorf(codes.Internal, |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 655 | "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, groupMod.GetCommand()) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 656 | } |
| 657 | |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 658 | // updateMeterTable updates the meter table of that logical device |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 659 | func (agent *LogicalAgent) updateMeterTable(ctx context.Context, meterMod *ofp.OfpMeterMod) error { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 660 | logger.Debug("updateMeterTable") |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 661 | if meterMod == nil { |
| 662 | return nil |
| 663 | } |
| 664 | switch meterMod.GetCommand() { |
| 665 | case ofp.OfpMeterModCommand_OFPMC_ADD: |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 666 | return agent.meterAdd(ctx, meterMod) |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 667 | case ofp.OfpMeterModCommand_OFPMC_DELETE: |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 668 | return agent.meterDelete(ctx, meterMod) |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 669 | case ofp.OfpMeterModCommand_OFPMC_MODIFY: |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 670 | return agent.meterModify(ctx, meterMod) |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 671 | } |
| 672 | return status.Errorf(codes.Internal, |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 673 | "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, meterMod.GetCommand()) |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 674 | |
| 675 | } |
| 676 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 677 | func (agent *LogicalAgent) meterAdd(ctx context.Context, meterMod *ofp.OfpMeterMod) error { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 678 | logger.Debugw("meterAdd", log.Fields{"metermod": *meterMod}) |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 679 | if meterMod == nil { |
| 680 | return nil |
| 681 | } |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 682 | |
| 683 | meterEntry := fu.MeterEntryFromMeterMod(meterMod) |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 684 | agent.meterLock.Lock() |
| 685 | //check if the meter already exists or not |
| 686 | _, ok := agent.meters[meterMod.MeterId] |
| 687 | if ok { |
| 688 | logger.Infow("Meter-already-exists", log.Fields{"meter": *meterMod}) |
| 689 | agent.meterLock.Unlock() |
| 690 | return nil |
| 691 | } |
| 692 | |
| 693 | mChunk := MeterChunk{ |
| 694 | meter: meterEntry, |
| 695 | } |
| 696 | //Add to map and acquire the per meter lock |
| 697 | agent.meters[meterMod.MeterId] = &mChunk |
| 698 | mChunk.lock.Lock() |
| 699 | defer mChunk.lock.Unlock() |
| 700 | agent.meterLock.Unlock() |
| 701 | meterID := strconv.Itoa(int(meterMod.MeterId)) |
| 702 | if err := agent.clusterDataProxy.AddWithID(ctx, "meters/"+agent.logicalDeviceID, meterID, meterEntry); err != nil { |
| 703 | logger.Errorw("failed-adding-meter", log.Fields{"deviceID": agent.logicalDeviceID, "meterID": meterID, "err": err}) |
| 704 | //Revert the map |
| 705 | agent.meterLock.Lock() |
| 706 | delete(agent.meters, meterMod.MeterId) |
| 707 | agent.meterLock.Unlock() |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 708 | return err |
| 709 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 710 | |
| 711 | logger.Debugw("Meter-added-successfully", log.Fields{"Added-meter": meterEntry}) |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 712 | return nil |
| 713 | } |
| 714 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 715 | func (agent *LogicalAgent) meterDelete(ctx context.Context, meterMod *ofp.OfpMeterMod) error { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 716 | logger.Debug("meterDelete", log.Fields{"meterMod": *meterMod}) |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 717 | if meterMod == nil { |
| 718 | return nil |
| 719 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 720 | agent.meterLock.RLock() |
| 721 | meterChunk, ok := agent.meters[meterMod.MeterId] |
| 722 | agent.meterLock.RUnlock() |
| 723 | if ok { |
| 724 | //Dont let anyone to do any changes to this meter until this is done. |
| 725 | //And wait if someone else is already making modifications. Do this with per meter lock. |
| 726 | meterChunk.lock.Lock() |
| 727 | defer meterChunk.lock.Unlock() |
| 728 | if err := agent.deleteFlowsOfMeter(ctx, meterMod.MeterId); err != nil { |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 729 | return err |
| 730 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 731 | //remove from the store and cache |
| 732 | if err := agent.removeLogicalDeviceMeter(ctx, meterMod.MeterId); err != nil { |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 733 | return err |
| 734 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 735 | logger.Debugw("meterDelete-success", log.Fields{"meterID": meterMod.MeterId}) |
| 736 | } else { |
| 737 | logger.Warnw("meter-not-found", log.Fields{"meterID": meterMod.MeterId}) |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 738 | } |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 739 | return nil |
| 740 | } |
| 741 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 742 | func (agent *LogicalAgent) meterModify(ctx context.Context, meterMod *ofp.OfpMeterMod) error { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 743 | logger.Debug("meterModify") |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 744 | if meterMod == nil { |
| 745 | return nil |
| 746 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 747 | newMeter := fu.MeterEntryFromMeterMod(meterMod) |
| 748 | agent.meterLock.RLock() |
| 749 | meterChunk, ok := agent.meters[newMeter.Config.MeterId] |
| 750 | agent.meterLock.RUnlock() |
| 751 | if !ok { |
| 752 | return fmt.Errorf("no-meter-to-modify:%d", newMeter.Config.MeterId) |
| 753 | } |
| 754 | //Release the map lock and syncronize per meter |
| 755 | meterChunk.lock.Lock() |
| 756 | defer meterChunk.lock.Unlock() |
| 757 | oldMeter := meterChunk.meter |
| 758 | newMeter.Stats.FlowCount = oldMeter.Stats.FlowCount |
| 759 | |
| 760 | if err := agent.updateLogicalDeviceMeter(ctx, newMeter, meterChunk); err != nil { |
| 761 | logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "meterID": newMeter.Config.MeterId}) |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 762 | return err |
| 763 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 764 | logger.Debugw("replaced-with-new-meter", log.Fields{"oldMeter": oldMeter, "newMeter": newMeter}) |
| 765 | return nil |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 766 | |
| 767 | } |
| 768 | |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 769 | func (agent *LogicalAgent) deleteFlowsOfMeter(ctx context.Context, meterID uint32) error { |
| 770 | logger.Infow("Delete-flows-matching-meter", log.Fields{"meter": meterID}) |
| 771 | agent.flowLock.Lock() |
| 772 | defer agent.flowLock.Unlock() |
| 773 | for flowID, flowChunk := range agent.flows { |
| 774 | if mID := fu.GetMeterIdFromFlow(flowChunk.flow); mID != 0 && mID == meterID { |
| 775 | logger.Debugw("Flow-to-be- deleted", log.Fields{"flow": flowChunk.flow}) |
| 776 | path := fmt.Sprintf("logical_flows/%s/%d", agent.logicalDeviceID, flowID) |
| 777 | if err := agent.clusterDataProxy.Remove(ctx, path); err != nil { |
| 778 | //TODO: Think on carrying on and deleting the remaining flows, instead of returning. |
| 779 | //Anyways this returns an error to controller which possibly results with a re-deletion. |
| 780 | //Then how can we handle the new deletion request(Same for group deletion)? |
| 781 | return fmt.Errorf("couldnt-deleted-flow-from-store-%s", path) |
| 782 | } |
| 783 | delete(agent.flows, flowID) |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 784 | } |
| 785 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 786 | return nil |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 787 | } |
| 788 | |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 789 | func (agent *LogicalAgent) updateFlowCountOfMeterStats(ctx context.Context, modCommand *ofp.OfpFlowMod, flow *ofp.OfpFlowStats, revertUpdate bool) bool { |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 790 | |
| 791 | flowCommand := modCommand.GetCommand() |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 792 | meterID := fu.GetMeterIdFromFlow(flow) |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 793 | logger.Debugw("Meter-id-in-flow-mod", log.Fields{"meterId": meterID}) |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 794 | if meterID == 0 { |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 795 | logger.Debugw("No-meter-present-in-the-flow", log.Fields{"flow": *flow}) |
| 796 | return true |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 797 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 798 | |
| 799 | if flowCommand != ofp.OfpFlowModCommand_OFPFC_ADD && flowCommand != ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT { |
| 800 | return true |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 801 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 802 | agent.meterLock.RLock() |
| 803 | meterChunk, ok := agent.meters[meterID] |
| 804 | agent.meterLock.RUnlock() |
| 805 | if !ok { |
| 806 | logger.Debugw("Meter-is-not-present-in-logical-device", log.Fields{"meterID": meterID}) |
| 807 | return true |
| 808 | } |
| 809 | |
| 810 | //acquire the meter lock |
| 811 | meterChunk.lock.Lock() |
| 812 | defer meterChunk.lock.Unlock() |
| 813 | |
| 814 | if flowCommand == ofp.OfpFlowModCommand_OFPFC_ADD { |
| 815 | if revertUpdate { |
| 816 | meterChunk.meter.Stats.FlowCount-- |
| 817 | } else { |
| 818 | meterChunk.meter.Stats.FlowCount++ |
| 819 | } |
| 820 | } else if flowCommand == ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT { |
| 821 | if revertUpdate { |
| 822 | meterChunk.meter.Stats.FlowCount++ |
| 823 | } else { |
| 824 | meterChunk.meter.Stats.FlowCount-- |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 825 | } |
| 826 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 827 | |
| 828 | // Update store and cache |
| 829 | if err := agent.updateLogicalDeviceMeter(ctx, meterChunk.meter, meterChunk); err != nil { |
| 830 | logger.Debugw("unable-to-update-meter-in-db", log.Fields{"logicalDevice": agent.logicalDeviceID, "meterID": meterID}) |
| 831 | return false |
| 832 | } |
| 833 | |
| 834 | logger.Debugw("updated-meter-flow-stats", log.Fields{"meterId": meterID}) |
| 835 | return true |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 836 | } |
| 837 | |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 838 | //flowAdd adds a flow to the flow table of that logical device |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 839 | func (agent *LogicalAgent) flowAdd(ctx context.Context, mod *ofp.OfpFlowMod) error { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 840 | logger.Debugw("flowAdd", log.Fields{"flow": mod}) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 841 | if mod == nil { |
| 842 | return nil |
| 843 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 844 | flow, err := fu.FlowStatsEntryFromFlowModMessage(mod) |
| 845 | if err != nil { |
| 846 | logger.Errorw("flowAdd-failed", log.Fields{"flowMod": mod, "err": err}) |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 847 | return err |
| 848 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 849 | var updated bool |
| 850 | var changed bool |
| 851 | if changed, updated, err = agent.decomposeAndAdd(ctx, flow, mod); err != nil { |
| 852 | logger.Errorw("flow-decompose-and-add-failed ", log.Fields{"flowMod": mod, "err": err}) |
| 853 | return err |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 854 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 855 | if changed && !updated { |
| 856 | if dbupdated := agent.updateFlowCountOfMeterStats(ctx, mod, flow, false); !dbupdated { |
| 857 | return fmt.Errorf("couldnt-updated-flow-stats-%s", strconv.FormatUint(flow.Id, 10)) |
| 858 | } |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 859 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 860 | return nil |
| 861 | |
| 862 | } |
| 863 | |
| 864 | func (agent *LogicalAgent) decomposeAndAdd(ctx context.Context, flow *ofp.OfpFlowStats, mod *ofp.OfpFlowMod) (bool, bool, error) { |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 865 | changed := false |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 866 | updated := false |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 867 | alreadyExist := true |
| 868 | var flowToReplace *ofp.OfpFlowStats |
| 869 | |
| 870 | //if flow is not found in the map, create a new entry, otherwise get the existing one. |
| 871 | agent.flowLock.Lock() |
| 872 | flowChunk, ok := agent.flows[flow.Id] |
| 873 | if !ok { |
| 874 | flowChunk = &FlowChunk{ |
| 875 | flow: flow, |
| 876 | } |
| 877 | agent.flows[flow.Id] = flowChunk |
| 878 | alreadyExist = false |
| 879 | flowChunk.lock.Lock() //acquire chunk lock before releasing map lock |
| 880 | defer flowChunk.lock.Unlock() |
| 881 | agent.flowLock.Unlock() |
| 882 | } else { |
| 883 | agent.flowLock.Unlock() //release map lock before acquiring chunk lock |
| 884 | flowChunk.lock.Lock() |
| 885 | defer flowChunk.lock.Unlock() |
| 886 | } |
| 887 | |
| 888 | if !alreadyExist { |
| 889 | flowID := strconv.FormatUint(flow.Id, 10) |
| 890 | if err := agent.clusterDataProxy.AddWithID(ctx, "logical_flows/"+agent.logicalDeviceID, flowID, flow); err != nil { |
| 891 | logger.Errorw("failed-adding-flow-to-db", log.Fields{"deviceID": agent.logicalDeviceID, "flowID": flowID, "err": err}) |
| 892 | //Revert the map |
| 893 | //TODO: Solve the condition:If we have two flow Adds of the same flow (at least same priority and match) in quick succession |
| 894 | //then if the first one fails while the second one was waiting on the flowchunk, we will end up with an instance of flowChunk that is no longer in the map. |
| 895 | agent.flowLock.Lock() |
| 896 | delete(agent.flows, flow.Id) |
| 897 | agent.flowLock.Unlock() |
| 898 | return changed, updated, err |
| 899 | } |
| 900 | } |
| 901 | flows := make([]*ofp.OfpFlowStats, 0) |
| 902 | updatedFlows := make([]*ofp.OfpFlowStats, 0) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 903 | checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0 |
| 904 | if checkOverlap { |
| 905 | if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 { |
| 906 | // TODO: should this error be notified other than being logged? |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 907 | logger.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceID}) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 908 | } else { |
Matt Jeanneret | 518b5a4 | 2019-10-29 10:30:46 -0400 | [diff] [blame] | 909 | // Add flow |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 910 | changed = true |
| 911 | } |
| 912 | } else { |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 913 | if alreadyExist { |
| 914 | flowToReplace = flowChunk.flow |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 915 | if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 { |
khenaidoo | 8b4abbf | 2020-04-24 17:04:30 -0400 | [diff] [blame] | 916 | flow.ByteCount = flowToReplace.ByteCount |
| 917 | flow.PacketCount = flowToReplace.PacketCount |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 918 | } |
khenaidoo | 8b4abbf | 2020-04-24 17:04:30 -0400 | [diff] [blame] | 919 | if !proto.Equal(flowToReplace, flow) { |
Matt Jeanneret | 518b5a4 | 2019-10-29 10:30:46 -0400 | [diff] [blame] | 920 | changed = true |
| 921 | updated = true |
| 922 | } |
| 923 | } else { |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 924 | changed = true |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 925 | } |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 926 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 927 | logger.Debugw("flowAdd-changed", log.Fields{"changed": changed, "updated": updated}) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 928 | if changed { |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 929 | updatedFlows = append(updatedFlows, flow) |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 930 | var flowMetadata voltha.FlowMetadata |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 931 | lMeters, _ := agent.ListLogicalDeviceMeters(ctx) |
| 932 | if err := agent.GetMeterConfig(updatedFlows, lMeters.Items, &flowMetadata); err != nil { |
| 933 | logger.Error("Meter-referred-in-flow-not-present") |
| 934 | return changed, updated, err |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 935 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 936 | flowGroups, _ := agent.ListLogicalDeviceFlowGroups(ctx) |
| 937 | deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: updatedFlows}, *flowGroups) |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 938 | if err != nil { |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 939 | return changed, updated, err |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 940 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 941 | |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 942 | logger.Debugw("rules", log.Fields{"rules": deviceRules.String()}) |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 943 | // Update store and cache |
| 944 | if updated { |
| 945 | if err := agent.updateLogicalDeviceFlow(ctx, flow, flowChunk); err != nil { |
| 946 | return changed, updated, err |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 947 | } |
| 948 | } |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 949 | respChannels := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, &flowMetadata) |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 950 | // Create the go routines to wait |
| 951 | go func() { |
| 952 | // Wait for completion |
| 953 | if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChannels...); res != nil { |
khenaidoo | 8b4abbf | 2020-04-24 17:04:30 -0400 | [diff] [blame] | 954 | logger.Infow("failed-to-add-flows-will-attempt-deletion", log.Fields{"errors": res, "logical-device-id": agent.logicalDeviceID}) |
| 955 | // Revert added flows |
| 956 | if err := agent.revertAddedFlows(context.Background(), mod, flow, flowToReplace, deviceRules, &flowMetadata); err != nil { |
| 957 | logger.Errorw("failure-to-delete-flows-after-failed-addition", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err}) |
| 958 | } |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 959 | } |
| 960 | }() |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 961 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 962 | return changed, updated, nil |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 963 | } |
| 964 | |
khenaidoo | 8b4abbf | 2020-04-24 17:04:30 -0400 | [diff] [blame] | 965 | // revertAddedFlows reverts flows after the flowAdd request has failed. All flows corresponding to that flowAdd request |
| 966 | // will be reverted, both from the logical devices and the devices. |
| 967 | func (agent *LogicalAgent) revertAddedFlows(ctx context.Context, mod *ofp.OfpFlowMod, addedFlow *ofp.OfpFlowStats, replacedFlow *ofp.OfpFlowStats, deviceRules *fu.DeviceRules, metadata *voltha.FlowMetadata) error { |
| 968 | logger.Debugw("revertFlowAdd", log.Fields{"added-flow": addedFlow, "replaced-flow": replacedFlow, "device-rules": deviceRules, "metadata": metadata}) |
khenaidoo | 8b4abbf | 2020-04-24 17:04:30 -0400 | [diff] [blame] | 969 | |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 970 | agent.flowLock.RLock() |
| 971 | flowChunk, ok := agent.flows[addedFlow.Id] |
| 972 | agent.flowLock.RUnlock() |
| 973 | if !ok { |
khenaidoo | 8b4abbf | 2020-04-24 17:04:30 -0400 | [diff] [blame] | 974 | // Not found - do nothing |
| 975 | log.Debugw("flow-not-found", log.Fields{"added-flow": addedFlow}) |
| 976 | return nil |
| 977 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 978 | //Leave the map lock and syncronize per flow |
| 979 | flowChunk.lock.Lock() |
| 980 | defer flowChunk.lock.Unlock() |
khenaidoo | 8b4abbf | 2020-04-24 17:04:30 -0400 | [diff] [blame] | 981 | |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 982 | if replacedFlow != nil { |
| 983 | if err := agent.updateLogicalDeviceFlow(ctx, replacedFlow, flowChunk); err != nil { |
| 984 | return err |
| 985 | } |
| 986 | } else { |
| 987 | if err := agent.removeLogicalDeviceFlow(ctx, addedFlow.Id); err != nil { |
| 988 | return err |
khenaidoo | a29a471 | 2020-05-05 10:17:17 -0400 | [diff] [blame] | 989 | } |
khenaidoo | 8b4abbf | 2020-04-24 17:04:30 -0400 | [diff] [blame] | 990 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 991 | // Revert meters |
| 992 | if changedMeterStats := agent.updateFlowCountOfMeterStats(ctx, mod, addedFlow, true); !changedMeterStats { |
| 993 | return fmt.Errorf("Unable-to-revert-meterstats-for-flow-%s", strconv.FormatUint(addedFlow.Id, 10)) |
khenaidoo | 8b4abbf | 2020-04-24 17:04:30 -0400 | [diff] [blame] | 994 | } |
| 995 | |
| 996 | // Update the devices |
| 997 | respChnls := agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, metadata) |
| 998 | |
| 999 | // Wait for the responses |
| 1000 | go func() { |
| 1001 | // Since this action is taken following an add failure, we may also receive a failure for the revert |
| 1002 | if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil { |
| 1003 | logger.Warnw("failure-reverting-added-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res}) |
| 1004 | } |
| 1005 | }() |
| 1006 | |
| 1007 | return nil |
| 1008 | } |
| 1009 | |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1010 | // GetMeterConfig returns meter config |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1011 | func (agent *LogicalAgent) GetMeterConfig(flows []*ofp.OfpFlowStats, meters []*ofp.OfpMeterEntry, metadata *voltha.FlowMetadata) error { |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 1012 | m := make(map[uint32]bool) |
| 1013 | for _, flow := range flows { |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1014 | if flowMeterID := fu.GetMeterIdFromFlow(flow); flowMeterID != 0 && !m[flowMeterID] { |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 1015 | foundMeter := false |
| 1016 | // Meter is present in the flow , Get from logical device |
| 1017 | for _, meter := range meters { |
| 1018 | if flowMeterID == meter.Config.MeterId { |
| 1019 | metadata.Meters = append(metadata.Meters, meter.Config) |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1020 | logger.Debugw("Found meter in logical device", |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 1021 | log.Fields{"meterID": flowMeterID, "meter-band": meter.Config}) |
| 1022 | m[flowMeterID] = true |
| 1023 | foundMeter = true |
| 1024 | break |
| 1025 | } |
| 1026 | } |
| 1027 | if !foundMeter { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1028 | logger.Errorw("Meter-referred-by-flow-is-not-found-in-logicaldevice", |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1029 | log.Fields{"meterID": flowMeterID, "Available-meters": meters, "flow": *flow}) |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1030 | return fmt.Errorf("Meter-referred-by-flow-is-not-found-in-logicaldevice.MeterId-%d", flowMeterID) |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 1031 | } |
| 1032 | } |
| 1033 | } |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1034 | logger.Debugw("meter-bands-for-flows", log.Fields{"flows": len(flows), "metadata": metadata}) |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 1035 | return nil |
| 1036 | |
| 1037 | } |
| 1038 | |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1039 | //flowDelete deletes a flow from the flow table of that logical device |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1040 | func (agent *LogicalAgent) flowDelete(ctx context.Context, mod *ofp.OfpFlowMod) error { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1041 | logger.Debug("flowDelete") |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1042 | if mod == nil { |
| 1043 | return nil |
| 1044 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1045 | |
| 1046 | fs, err := fu.FlowStatsEntryFromFlowModMessage(mod) |
| 1047 | if err != nil { |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1048 | return err |
| 1049 | } |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1050 | |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1051 | //build a list of what to delete |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 1052 | toDelete := make([]*ofp.OfpFlowStats, 0) |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1053 | toDeleteChunks := make([]*FlowChunk, 0) |
| 1054 | //Lock the map to search the matched flows |
| 1055 | agent.flowLock.RLock() |
| 1056 | for _, f := range agent.flows { |
| 1057 | if fu.FlowMatch(f.flow, fs) { |
| 1058 | toDelete = append(toDelete, f.flow) |
| 1059 | toDeleteChunks = append(toDeleteChunks, f) |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 1060 | continue |
| 1061 | } |
| 1062 | // Check wild card match |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1063 | if fu.FlowMatchesMod(f.flow, mod) { |
| 1064 | toDelete = append(toDelete, f.flow) |
| 1065 | toDeleteChunks = append(toDeleteChunks, f) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1066 | } |
| 1067 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1068 | agent.flowLock.RUnlock() |
| 1069 | //Delete the matched flows |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 1070 | if len(toDelete) > 0 { |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1071 | logger.Debugw("flowDelete", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "toDelete": len(toDelete)}) |
| 1072 | var meters []*ofp.OfpMeterEntry |
| 1073 | var flowGroups []*ofp.OfpGroupEntry |
| 1074 | if ofpMeters, err := agent.ListLogicalDeviceMeters(ctx); err != nil { |
| 1075 | meters = ofpMeters.Items |
| 1076 | } |
| 1077 | |
| 1078 | if groups, err := agent.ListLogicalDeviceFlowGroups(ctx); err != nil { |
| 1079 | flowGroups = groups.Items |
| 1080 | } |
| 1081 | |
| 1082 | for _, fc := range toDeleteChunks { |
| 1083 | if err := agent.deleteFlowAndUpdateMeterStats(ctx, mod, fc); err != nil { |
| 1084 | return err |
| 1085 | } |
| 1086 | } |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 1087 | var flowMetadata voltha.FlowMetadata |
| 1088 | if err := agent.GetMeterConfig(toDelete, meters, &flowMetadata); err != nil { // This should never happen |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1089 | logger.Error("Meter-referred-in-flows-not-present") |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1090 | return err |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 1091 | } |
khenaidoo | 787224a | 2020-04-16 18:08:47 -0400 | [diff] [blame] | 1092 | var respChnls []coreutils.Response |
| 1093 | var partialRoute bool |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1094 | var deviceRules *fu.DeviceRules |
| 1095 | deviceRules, err = agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: toDelete}, ofp.FlowGroups{Items: flowGroups}) |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1096 | if err != nil { |
khenaidoo | 787224a | 2020-04-16 18:08:47 -0400 | [diff] [blame] | 1097 | // A no route error means no route exists between the ports specified in the flow. This can happen when the |
| 1098 | // child device is deleted and a request to delete flows from the parent device is received |
| 1099 | if !errors.Is(err, route.ErrNoRoute) { |
| 1100 | logger.Errorw("unexpected-error-received", log.Fields{"flows-to-delete": toDelete, "error": err}) |
| 1101 | return err |
| 1102 | } |
| 1103 | partialRoute = true |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1104 | } |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 1105 | |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1106 | // Update the devices |
khenaidoo | 787224a | 2020-04-16 18:08:47 -0400 | [diff] [blame] | 1107 | if partialRoute { |
| 1108 | respChnls = agent.deleteFlowsFromParentDevice(ctx, ofp.Flows{Items: toDelete}, &flowMetadata) |
| 1109 | } else { |
| 1110 | respChnls = agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &flowMetadata) |
| 1111 | } |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1112 | |
| 1113 | // Wait for the responses |
| 1114 | go func() { |
| 1115 | // Wait for completion |
| 1116 | if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1117 | logger.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res}) |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1118 | // TODO: Revert the flow deletion |
| 1119 | } |
| 1120 | }() |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1121 | } |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1122 | //TODO: send announcement on delete |
| 1123 | return nil |
| 1124 | } |
| 1125 | |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1126 | func (agent *LogicalAgent) deleteFlowAndUpdateMeterStats(ctx context.Context, mod *ofp.OfpFlowMod, chunk *FlowChunk) error { |
| 1127 | chunk.lock.Lock() |
| 1128 | defer chunk.lock.Unlock() |
| 1129 | if changedMeter := agent.updateFlowCountOfMeterStats(ctx, mod, chunk.flow, false); !changedMeter { |
| 1130 | return fmt.Errorf("Cannot-delete-flow-%s. Meter-update-failed", chunk.flow) |
| 1131 | } |
| 1132 | // Update store and cache |
| 1133 | if err := agent.removeLogicalDeviceFlow(ctx, chunk.flow.Id); err != nil { |
| 1134 | return fmt.Errorf("Cannot-delete-flows-%s. Delete-from-store-failed", chunk.flow) |
| 1135 | } |
| 1136 | return nil |
| 1137 | } |
| 1138 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1139 | func (agent *LogicalAgent) addFlowsAndGroupsToDevices(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1140 | 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] | 1141 | |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 1142 | responses := make([]coreutils.Response, 0) |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1143 | for deviceID, value := range deviceRules.GetRules() { |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 1144 | response := coreutils.NewResponse() |
| 1145 | responses = append(responses, response) |
| 1146 | go func(deviceId string, value *fu.FlowsAndGroups) { |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1147 | ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout) |
| 1148 | defer cancel() |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 1149 | if err := agent.deviceMgr.addFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1150 | logger.Errorw("flow-add-failed", log.Fields{"deviceID": deviceId, "error": err}) |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 1151 | response.Error(status.Errorf(codes.Internal, "flow-add-failed: %s", deviceId)) |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 1152 | } |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 1153 | response.Done() |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1154 | }(deviceID, value) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1155 | } |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1156 | // Return responses (an array of channels) for the caller to wait for a response from the far end. |
| 1157 | return responses |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 1158 | } |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1159 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1160 | func (agent *LogicalAgent) deleteFlowsAndGroupsFromDevices(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1161 | logger.Debugw("send-delete-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID}) |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 1162 | |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 1163 | responses := make([]coreutils.Response, 0) |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1164 | for deviceID, value := range deviceRules.GetRules() { |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 1165 | response := coreutils.NewResponse() |
| 1166 | responses = append(responses, response) |
| 1167 | go func(deviceId string, value *fu.FlowsAndGroups) { |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1168 | ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout) |
| 1169 | defer cancel() |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 1170 | if err := agent.deviceMgr.deleteFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil { |
khenaidoo | 787224a | 2020-04-16 18:08:47 -0400 | [diff] [blame] | 1171 | logger.Errorw("flow-delete-failed", log.Fields{"deviceID": deviceId, "error": err}) |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 1172 | response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s", deviceId)) |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 1173 | } |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 1174 | response.Done() |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1175 | }(deviceID, value) |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 1176 | } |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1177 | return responses |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 1178 | } |
| 1179 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1180 | func (agent *LogicalAgent) updateFlowsAndGroupsOfDevice(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1181 | logger.Debugw("send-update-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID}) |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 1182 | |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 1183 | responses := make([]coreutils.Response, 0) |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1184 | for deviceID, value := range deviceRules.GetRules() { |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 1185 | response := coreutils.NewResponse() |
| 1186 | responses = append(responses, response) |
| 1187 | go func(deviceId string, value *fu.FlowsAndGroups) { |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1188 | ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout) |
| 1189 | defer cancel() |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 1190 | if err := agent.deviceMgr.updateFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil { |
khenaidoo | 787224a | 2020-04-16 18:08:47 -0400 | [diff] [blame] | 1191 | logger.Errorw("flow-update-failed", log.Fields{"deviceID": deviceId, "error": err}) |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 1192 | response.Error(status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId)) |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 1193 | } |
Kent Hagerman | 8da2f1e | 2019-11-25 17:28:09 -0500 | [diff] [blame] | 1194 | response.Done() |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1195 | }(deviceID, value) |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 1196 | } |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1197 | return responses |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1198 | } |
| 1199 | |
khenaidoo | 787224a | 2020-04-16 18:08:47 -0400 | [diff] [blame] | 1200 | // getUNILogicalPortNo returns the UNI logical port number specified in the flow |
| 1201 | func (agent *LogicalAgent) getUNILogicalPortNo(flow *ofp.OfpFlowStats) (uint32, error) { |
| 1202 | var uniPort uint32 |
| 1203 | inPortNo := fu.GetInPort(flow) |
| 1204 | outPortNo := fu.GetOutPort(flow) |
| 1205 | if agent.isNNIPort(inPortNo) { |
| 1206 | uniPort = outPortNo |
| 1207 | } else if agent.isNNIPort(outPortNo) { |
| 1208 | uniPort = inPortNo |
| 1209 | } |
| 1210 | if uniPort != 0 { |
| 1211 | return uniPort, nil |
| 1212 | } |
| 1213 | return 0, status.Errorf(codes.NotFound, "no-uni-port: %v", flow) |
| 1214 | } |
| 1215 | |
| 1216 | func (agent *LogicalAgent) deleteFlowsFromParentDevice(ctx context.Context, flows ofp.Flows, metadata *voltha.FlowMetadata) []coreutils.Response { |
| 1217 | logger.Debugw("deleting-flows-from-parent-device", log.Fields{"logical-device-id": agent.logicalDeviceID, "flows": flows}) |
| 1218 | responses := make([]coreutils.Response, 0) |
| 1219 | for _, flow := range flows.Items { |
| 1220 | response := coreutils.NewResponse() |
| 1221 | responses = append(responses, response) |
| 1222 | uniPort, err := agent.getUNILogicalPortNo(flow) |
| 1223 | if err != nil { |
| 1224 | logger.Error("no-uni-port-in-flow", log.Fields{"deviceID": agent.rootDeviceID, "flow": flow, "error": err}) |
| 1225 | response.Error(err) |
| 1226 | response.Done() |
| 1227 | continue |
| 1228 | } |
| 1229 | logger.Debugw("uni-port", log.Fields{"flows": flows, "uni-port": uniPort}) |
| 1230 | go func(uniPort uint32, metadata *voltha.FlowMetadata) { |
| 1231 | ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout) |
| 1232 | defer cancel() |
| 1233 | if err := agent.deviceMgr.deleteParentFlows(ctx, agent.rootDeviceID, uniPort, metadata); err != nil { |
| 1234 | logger.Error("flow-delete-failed", log.Fields{"device-id": agent.rootDeviceID, "error": err}) |
| 1235 | response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s %v", agent.rootDeviceID, err)) |
| 1236 | } |
| 1237 | response.Done() |
| 1238 | }(uniPort, metadata) |
| 1239 | } |
| 1240 | return responses |
| 1241 | } |
| 1242 | |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1243 | //flowDeleteStrict deletes a flow from the flow table of that logical device |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1244 | func (agent *LogicalAgent) flowDeleteStrict(ctx context.Context, mod *ofp.OfpFlowMod) error { |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1245 | logger.Debugw("flowDeleteStrict", log.Fields{"mod": mod}) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1246 | if mod == nil { |
| 1247 | return nil |
| 1248 | } |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1249 | |
Scott Baker | fdea1e3 | 2020-02-21 15:35:41 -0800 | [diff] [blame] | 1250 | flow, err := fu.FlowStatsEntryFromFlowModMessage(mod) |
| 1251 | if err != nil { |
| 1252 | return err |
| 1253 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1254 | logger.Debugw("flow-id-in-flow-delete-strict", log.Fields{"flowID": flow.Id}) |
| 1255 | agent.flowLock.RLock() |
| 1256 | flowChunk, ok := agent.flows[flow.Id] |
| 1257 | agent.flowLock.RUnlock() |
| 1258 | if !ok { |
| 1259 | logger.Debugw("Skipping-flow-delete-strict-request. No-flow-found", log.Fields{"flowMod": mod}) |
| 1260 | return nil |
| 1261 | } |
| 1262 | //Release the map lock and syncronize per flow |
| 1263 | flowChunk.lock.Lock() |
| 1264 | defer flowChunk.lock.Unlock() |
| 1265 | |
| 1266 | var meters []*ofp.OfpMeterEntry |
| 1267 | var flowGroups []*ofp.OfpGroupEntry |
| 1268 | if ofMeters, er := agent.ListLogicalDeviceMeters(ctx); er == nil { |
| 1269 | meters = ofMeters.Items |
| 1270 | } |
| 1271 | if ofGroups, er := agent.ListLogicalDeviceFlowGroups(ctx); er == nil { |
| 1272 | flowGroups = ofGroups.Items |
| 1273 | } |
| 1274 | if changedMeter := agent.updateFlowCountOfMeterStats(ctx, mod, flow, false); !changedMeter { |
| 1275 | return fmt.Errorf("Cannot delete flow - %s. Meter update failed", flow) |
| 1276 | } |
| 1277 | |
| 1278 | var flowMetadata voltha.FlowMetadata |
| 1279 | flowsToDelete := []*ofp.OfpFlowStats{flowChunk.flow} |
| 1280 | if err := agent.GetMeterConfig(flowsToDelete, meters, &flowMetadata); err != nil { |
| 1281 | logger.Error("meter-referred-in-flows-not-present") |
| 1282 | return err |
| 1283 | } |
| 1284 | var respChnls []coreutils.Response |
| 1285 | var partialRoute bool |
| 1286 | deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: flowsToDelete}, ofp.FlowGroups{Items: flowGroups}) |
| 1287 | if err != nil { |
| 1288 | // A no route error means no route exists between the ports specified in the flow. This can happen when the |
| 1289 | // child device is deleted and a request to delete flows from the parent device is received |
| 1290 | if !errors.Is(err, route.ErrNoRoute) { |
| 1291 | logger.Errorw("unexpected-error-received", log.Fields{"flows-to-delete": flowsToDelete, "error": err}) |
| 1292 | return err |
| 1293 | } |
| 1294 | partialRoute = true |
| 1295 | } |
| 1296 | |
| 1297 | // Update the model |
| 1298 | if err := agent.removeLogicalDeviceFlow(ctx, flow.Id); err != nil { |
| 1299 | return err |
| 1300 | } |
| 1301 | // Update the devices |
| 1302 | if partialRoute { |
| 1303 | respChnls = agent.deleteFlowsFromParentDevice(ctx, ofp.Flows{Items: flowsToDelete}, &flowMetadata) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1304 | } else { |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1305 | respChnls = agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &flowMetadata) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1306 | } |
| 1307 | |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1308 | // Wait for completion |
| 1309 | go func() { |
| 1310 | if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil { |
| 1311 | logger.Warnw("failure-deleting-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res}) |
| 1312 | //TODO: Revert flow changes |
Manikkaraj k | b1a1092 | 2019-07-29 12:10:34 -0400 | [diff] [blame] | 1313 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1314 | }() |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 1315 | |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1316 | return nil |
| 1317 | } |
| 1318 | |
| 1319 | //flowModify modifies a flow from the flow table of that logical device |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1320 | func (agent *LogicalAgent) flowModify(mod *ofp.OfpFlowMod) error { |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1321 | return errors.New("flowModify not implemented") |
| 1322 | } |
| 1323 | |
| 1324 | //flowModifyStrict deletes a flow from the flow table of that logical device |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1325 | func (agent *LogicalAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error { |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1326 | return errors.New("flowModifyStrict not implemented") |
| 1327 | } |
| 1328 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1329 | func (agent *LogicalAgent) groupAdd(ctx context.Context, groupMod *ofp.OfpGroupMod) error { |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1330 | if groupMod == nil { |
| 1331 | return nil |
| 1332 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1333 | logger.Debugw("groupAdd", log.Fields{"GroupId": groupMod.GroupId}) |
| 1334 | agent.groupLock.Lock() |
| 1335 | _, ok := agent.groups[groupMod.GroupId] |
| 1336 | if ok { |
| 1337 | agent.groupLock.Unlock() |
| 1338 | return fmt.Errorf("Group %d already exists", groupMod.GroupId) |
| 1339 | } |
| 1340 | |
| 1341 | groupEntry := fu.GroupEntryFromGroupMod(groupMod) |
| 1342 | groupChunk := GroupChunk{ |
| 1343 | group: groupEntry, |
| 1344 | } |
| 1345 | //add to map |
| 1346 | agent.groups[groupMod.GroupId] = &groupChunk |
| 1347 | groupChunk.lock.Lock() |
| 1348 | defer groupChunk.lock.Unlock() |
| 1349 | agent.groupLock.Unlock() |
| 1350 | //add to the kv store |
| 1351 | path := fmt.Sprintf("groups/%s", agent.logicalDeviceID) |
| 1352 | groupID := strconv.Itoa(int(groupMod.GroupId)) |
| 1353 | if err := agent.clusterDataProxy.AddWithID(ctx, path, groupID, groupEntry); err != nil { |
| 1354 | logger.Errorw("failed-adding-group", log.Fields{"deviceID": agent.logicalDeviceID, "groupID": groupID, "err": err}) |
| 1355 | agent.groupLock.Lock() |
| 1356 | delete(agent.groups, groupMod.GroupId) |
| 1357 | agent.groupLock.Unlock() |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1358 | return err |
| 1359 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1360 | deviceRules := fu.NewDeviceRules() |
| 1361 | deviceRules.CreateEntryIfNotExist(agent.rootDeviceID) |
| 1362 | fg := fu.NewFlowsAndGroups() |
| 1363 | fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod)) |
| 1364 | deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1365 | |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1366 | logger.Debugw("rules", log.Fields{"rules for group-add": deviceRules.String()}) |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 1367 | |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1368 | // Update the devices |
| 1369 | respChnls := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, &voltha.FlowMetadata{}) |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 1370 | |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1371 | // Wait for completion |
| 1372 | go func() { |
| 1373 | if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil { |
| 1374 | logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res}) |
| 1375 | //TODO: Revert flow changes |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1376 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1377 | }() |
| 1378 | return nil |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1379 | } |
| 1380 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1381 | func (agent *LogicalAgent) groupDelete(ctx context.Context, groupMod *ofp.OfpGroupMod) error { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1382 | logger.Debug("groupDelete") |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1383 | if groupMod == nil { |
| 1384 | return nil |
| 1385 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1386 | affectedFlows := make([]*ofp.OfpFlowStats, 0) |
| 1387 | affectedGroups := make([]*ofp.OfpGroupEntry, 0) |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1388 | var groupsChanged bool |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1389 | groupID := groupMod.GroupId |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1390 | var err error |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1391 | if groupID == uint32(ofp.OfpGroup_OFPG_ALL) { |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1392 | if err := func() error { |
| 1393 | agent.groupLock.Lock() |
| 1394 | defer agent.groupLock.Unlock() |
| 1395 | for key, groupChunk := range agent.groups { |
| 1396 | //Remove from store and cache. Do this in a one time lock allocation. |
| 1397 | path := fmt.Sprintf("groups/%s/%d", agent.logicalDeviceID, key) |
| 1398 | if err := agent.clusterDataProxy.Remove(ctx, path); err != nil { |
| 1399 | return fmt.Errorf("couldnt-deleted-group-from-store-%s", path) |
| 1400 | } |
| 1401 | delete(agent.groups, groupID) |
| 1402 | var flows []*ofp.OfpFlowStats |
| 1403 | if flows, err = agent.deleteFlowsOfGroup(ctx, key); err != nil { |
| 1404 | logger.Errorw("cannot-update-flow-for-group-delete", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "groupID": key}) |
| 1405 | return err |
| 1406 | } |
| 1407 | affectedFlows = append(affectedFlows, flows...) |
| 1408 | affectedGroups = append(affectedGroups, groupChunk.group) |
| 1409 | } |
| 1410 | return nil |
| 1411 | }(); err != nil { |
| 1412 | return err |
| 1413 | } |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1414 | groupsChanged = true |
| 1415 | } else { |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1416 | agent.groupLock.RLock() |
| 1417 | groupChunk, ok := agent.groups[groupID] |
| 1418 | agent.groupLock.RUnlock() |
| 1419 | if !ok { |
| 1420 | logger.Warnw("group-not-found", log.Fields{"groupID": groupID}) |
| 1421 | return nil |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1422 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1423 | groupChunk.lock.Lock() |
| 1424 | defer groupChunk.lock.Unlock() |
| 1425 | var flows []*ofp.OfpFlowStats |
| 1426 | if flows, err = agent.deleteFlowsOfGroup(ctx, groupID); err != nil { |
| 1427 | logger.Errorw("cannot-update-flow-for-group-delete", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "groupID": groupID}) |
| 1428 | return err |
| 1429 | } |
| 1430 | //remove from store |
| 1431 | if err := agent.removeLogicalDeviceFlowGroup(ctx, groupID); err != nil { |
| 1432 | return err |
| 1433 | } |
| 1434 | affectedFlows = append(affectedFlows, flows...) |
| 1435 | affectedGroups = append(affectedGroups, groupChunk.group) |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1436 | groupsChanged = true |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1437 | |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1438 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1439 | |
| 1440 | if err != nil || groupsChanged { |
| 1441 | var deviceRules *fu.DeviceRules |
| 1442 | deviceRules, err = agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: affectedFlows}, ofp.FlowGroups{Items: affectedGroups}) |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1443 | if err != nil { |
| 1444 | return err |
| 1445 | } |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1446 | logger.Debugw("rules", log.Fields{"rules": deviceRules.String()}) |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 1447 | |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1448 | // Update the devices |
| 1449 | respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, nil) |
| 1450 | |
| 1451 | // Wait for completion |
| 1452 | go func() { |
| 1453 | if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1454 | logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res}) |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1455 | //TODO: Revert flow changes |
| 1456 | } |
| 1457 | }() |
khenaidoo | 43c8212 | 2018-11-22 18:38:28 -0500 | [diff] [blame] | 1458 | } |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1459 | return nil |
| 1460 | } |
| 1461 | |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1462 | func (agent *LogicalAgent) deleteFlowsOfGroup(ctx context.Context, groupID uint32) ([]*ofp.OfpFlowStats, error) { |
| 1463 | logger.Infow("Delete-flows-matching-group", log.Fields{"groupID": groupID}) |
| 1464 | var flowsRemoved []*ofp.OfpFlowStats |
| 1465 | agent.flowLock.Lock() |
| 1466 | defer agent.flowLock.Unlock() |
| 1467 | for flowID, flowChunk := range agent.flows { |
| 1468 | if fu.FlowHasOutGroup(flowChunk.flow, groupID) { |
| 1469 | path := fmt.Sprintf("logical_flows/%s/%d", agent.logicalDeviceID, flowID) |
| 1470 | if err := agent.clusterDataProxy.Remove(ctx, path); err != nil { |
| 1471 | return nil, fmt.Errorf("couldnt-delete-flow-from-store-%s", path) |
| 1472 | } |
| 1473 | delete(agent.flows, flowID) |
| 1474 | flowsRemoved = append(flowsRemoved, flowChunk.flow) |
| 1475 | } |
| 1476 | } |
| 1477 | return flowsRemoved, nil |
| 1478 | } |
| 1479 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1480 | func (agent *LogicalAgent) groupModify(ctx context.Context, groupMod *ofp.OfpGroupMod) error { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1481 | logger.Debug("groupModify") |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1482 | if groupMod == nil { |
| 1483 | return nil |
| 1484 | } |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1485 | |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1486 | groupID := groupMod.GroupId |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1487 | agent.groupLock.RLock() |
| 1488 | groupChunk, ok := agent.groups[groupID] |
| 1489 | agent.groupLock.RUnlock() |
| 1490 | if !ok { |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1491 | return fmt.Errorf("group-absent:%d", groupID) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1492 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1493 | //Don't let any other thread to make modifications to this group till all done here. |
| 1494 | groupChunk.lock.Lock() |
| 1495 | defer groupChunk.lock.Unlock() |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1496 | //replace existing group entry with new group definition |
| 1497 | groupEntry := fu.GroupEntryFromGroupMod(groupMod) |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1498 | deviceRules := fu.NewDeviceRules() |
| 1499 | deviceRules.CreateEntryIfNotExist(agent.rootDeviceID) |
| 1500 | fg := fu.NewFlowsAndGroups() |
| 1501 | fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod)) |
| 1502 | deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg) |
khenaidoo | 0458db6 | 2019-06-20 08:50:36 -0400 | [diff] [blame] | 1503 | |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1504 | logger.Debugw("rules", log.Fields{"rules-for-group-modify": deviceRules.String()}) |
| 1505 | //update KV |
| 1506 | if err := agent.updateLogicalDeviceFlowGroup(ctx, groupEntry, groupChunk); err != nil { |
| 1507 | logger.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID}) |
| 1508 | return err |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1509 | } |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 1510 | |
| 1511 | // Update the devices |
| 1512 | respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, &voltha.FlowMetadata{}) |
| 1513 | |
| 1514 | // Wait for completion |
| 1515 | go func() { |
| 1516 | if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil { |
| 1517 | logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res}) |
| 1518 | //TODO: Revert flow changes |
| 1519 | } |
| 1520 | }() |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1521 | return nil |
| 1522 | } |
| 1523 | |
| 1524 | // deleteLogicalPort removes the logical port |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1525 | func (agent *LogicalAgent) deleteLogicalPort(ctx context.Context, lPort *voltha.LogicalPort) error { |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1526 | if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil { |
| 1527 | return err |
| 1528 | } |
| 1529 | defer agent.requestQueue.RequestComplete() |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1530 | |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 1531 | logicalDevice := agent.getLogicalDeviceWithoutLock() |
| 1532 | |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 1533 | index := -1 |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 1534 | for i, logicalPort := range logicalDevice.Ports { |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1535 | if logicalPort.Id == lPort.Id { |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 1536 | index = i |
| 1537 | break |
| 1538 | } |
| 1539 | } |
| 1540 | if index >= 0 { |
Kent Hagerman | d9cc2e9 | 2019-11-04 13:28:15 -0500 | [diff] [blame] | 1541 | clonedPorts := clonePorts(logicalDevice.Ports) |
| 1542 | if index < len(clonedPorts)-1 { |
| 1543 | copy(clonedPorts[index:], clonedPorts[index+1:]) |
| 1544 | } |
| 1545 | clonedPorts[len(clonedPorts)-1] = nil |
| 1546 | clonedPorts = clonedPorts[:len(clonedPorts)-1] |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1547 | logger.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceID}) |
Kent Hagerman | d9cc2e9 | 2019-11-04 13:28:15 -0500 | [diff] [blame] | 1548 | if err := agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1549 | logger.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID}) |
khenaidoo | 0a822f9 | 2019-05-08 15:15:57 -0400 | [diff] [blame] | 1550 | return err |
| 1551 | } |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1552 | |
| 1553 | // Remove the logical port from cache |
| 1554 | agent.deleteLogicalPortsFromMap([]uint32{lPort.DevicePortNo}) |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1555 | // Reset the logical device routes |
| 1556 | go func() { |
| 1557 | if err := agent.buildRoutes(context.Background()); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1558 | logger.Warnw("device-routes-not-ready", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err}) |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1559 | } |
| 1560 | }() |
khenaidoo | 92e62c5 | 2018-10-03 14:02:54 -0400 | [diff] [blame] | 1561 | } |
| 1562 | return nil |
khenaidoo | b920354 | 2018-09-17 22:56:37 -0400 | [diff] [blame] | 1563 | } |
| 1564 | |
khenaidoo | 0a822f9 | 2019-05-08 15:15:57 -0400 | [diff] [blame] | 1565 | // deleteLogicalPorts removes the logical ports associated with that deviceId |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1566 | func (agent *LogicalAgent) deleteLogicalPorts(ctx context.Context, deviceID string) error { |
Andrea Campanella | 09400bd | 2020-04-02 11:58:04 +0200 | [diff] [blame] | 1567 | logger.Debugw("deleting-logical-ports", log.Fields{"device-id": deviceID}) |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1568 | if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil { |
| 1569 | return err |
| 1570 | } |
| 1571 | defer agent.requestQueue.RequestComplete() |
khenaidoo | 0a822f9 | 2019-05-08 15:15:57 -0400 | [diff] [blame] | 1572 | |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 1573 | logicalDevice := agent.getLogicalDeviceWithoutLock() |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1574 | lPortstoKeep := []*voltha.LogicalPort{} |
| 1575 | lPortsNoToDelete := []uint32{} |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 1576 | for _, logicalPort := range logicalDevice.Ports { |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1577 | if logicalPort.DeviceId != deviceID { |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1578 | lPortstoKeep = append(lPortstoKeep, logicalPort) |
| 1579 | } else { |
| 1580 | lPortsNoToDelete = append(lPortsNoToDelete, logicalPort.DevicePortNo) |
khenaidoo | 0a822f9 | 2019-05-08 15:15:57 -0400 | [diff] [blame] | 1581 | } |
| 1582 | } |
Andrea Campanella | 09400bd | 2020-04-02 11:58:04 +0200 | [diff] [blame] | 1583 | logger.Debugw("deleted-logical-ports", log.Fields{"ports": lPortstoKeep}) |
Kent Hagerman | d9cc2e9 | 2019-11-04 13:28:15 -0500 | [diff] [blame] | 1584 | if err := agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, lPortstoKeep); err != nil { |
Andrea Campanella | 09400bd | 2020-04-02 11:58:04 +0200 | [diff] [blame] | 1585 | logger.Errorw("logical-device-update-failed", log.Fields{"logical-device-id": agent.logicalDeviceID}) |
khenaidoo | 0a822f9 | 2019-05-08 15:15:57 -0400 | [diff] [blame] | 1586 | return err |
| 1587 | } |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1588 | // Remove the port from the cached logical ports set |
| 1589 | agent.deleteLogicalPortsFromMap(lPortsNoToDelete) |
| 1590 | |
| 1591 | // Reset the logical device routes |
| 1592 | go func() { |
| 1593 | if err := agent.buildRoutes(context.Background()); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1594 | logger.Warnw("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err}) |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1595 | } |
| 1596 | }() |
khenaidoo | 0a822f9 | 2019-05-08 15:15:57 -0400 | [diff] [blame] | 1597 | |
| 1598 | return nil |
| 1599 | } |
| 1600 | |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1601 | // enableLogicalPort enables the logical port |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1602 | func (agent *LogicalAgent) enableLogicalPort(ctx context.Context, lPortID string) error { |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1603 | if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil { |
| 1604 | return err |
| 1605 | } |
| 1606 | defer agent.requestQueue.RequestComplete() |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1607 | |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 1608 | logicalDevice := agent.getLogicalDeviceWithoutLock() |
| 1609 | |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1610 | index := -1 |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 1611 | for i, logicalPort := range logicalDevice.Ports { |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1612 | if logicalPort.Id == lPortID { |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1613 | index = i |
| 1614 | break |
| 1615 | } |
| 1616 | } |
| 1617 | if index >= 0 { |
Kent Hagerman | d9cc2e9 | 2019-11-04 13:28:15 -0500 | [diff] [blame] | 1618 | clonedPorts := clonePorts(logicalDevice.Ports) |
| 1619 | clonedPorts[index].OfpPort.Config = clonedPorts[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN) |
| 1620 | return agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1621 | } |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1622 | return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1623 | } |
| 1624 | |
| 1625 | // disableLogicalPort disabled the logical port |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1626 | func (agent *LogicalAgent) disableLogicalPort(ctx context.Context, lPortID string) error { |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1627 | if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil { |
| 1628 | return err |
| 1629 | } |
| 1630 | defer agent.requestQueue.RequestComplete() |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1631 | |
| 1632 | // Get the most up to date logical device |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 1633 | logicalDevice := agent.getLogicalDeviceWithoutLock() |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1634 | index := -1 |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 1635 | for i, logicalPort := range logicalDevice.Ports { |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1636 | if logicalPort.Id == lPortID { |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1637 | index = i |
| 1638 | break |
| 1639 | } |
| 1640 | } |
| 1641 | if index >= 0 { |
Kent Hagerman | d9cc2e9 | 2019-11-04 13:28:15 -0500 | [diff] [blame] | 1642 | clonedPorts := clonePorts(logicalDevice.Ports) |
| 1643 | clonedPorts[index].OfpPort.Config = (clonedPorts[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN) |
| 1644 | return agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1645 | } |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1646 | return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID) |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1647 | } |
| 1648 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1649 | func (agent *LogicalAgent) getPreCalculatedRoute(ingress, egress uint32) ([]route.Hop, error) { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1650 | logger.Debugw("ROUTE", log.Fields{"len": len(agent.deviceRoutes.Routes)}) |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1651 | for routeLink, route := range agent.deviceRoutes.Routes { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1652 | logger.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink}) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 1653 | if ingress == routeLink.Ingress && egress == routeLink.Egress { |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1654 | return route, nil |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 1655 | } |
| 1656 | } |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1657 | return nil, status.Errorf(codes.FailedPrecondition, "no route from:%d to:%d", ingress, egress) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 1658 | } |
| 1659 | |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1660 | // GetRoute returns route |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1661 | func (agent *LogicalAgent) GetRoute(ctx context.Context, ingressPortNo uint32, egressPortNo uint32) ([]route.Hop, error) { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1662 | logger.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo}) |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1663 | routes := make([]route.Hop, 0) |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 1664 | |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1665 | // Note: A port value of 0 is equivalent to a nil port |
| 1666 | |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 1667 | // Consider different possibilities |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1668 | if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1669 | logger.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo}) |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 1670 | if agent.isNNIPort(ingressPortNo) { |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 1671 | //This is a trap on the NNI Port |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1672 | if len(agent.deviceRoutes.Routes) == 0 { |
khenaidoo | 8f47419 | 2019-04-03 17:20:44 -0400 | [diff] [blame] | 1673 | // If there are no routes set (usually when the logical device has only NNI port(s), then just return an |
Humera Kouser | 4ff8901 | 2019-08-25 19:01:51 -0400 | [diff] [blame] | 1674 | // route with same IngressHop and EgressHop |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1675 | hop := route.Hop{DeviceID: agent.rootDeviceID, Ingress: ingressPortNo, Egress: ingressPortNo} |
khenaidoo | 8f47419 | 2019-04-03 17:20:44 -0400 | [diff] [blame] | 1676 | routes = append(routes, hop) |
| 1677 | routes = append(routes, hop) |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1678 | return routes, nil |
khenaidoo | 8f47419 | 2019-04-03 17:20:44 -0400 | [diff] [blame] | 1679 | } |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 1680 | //Return a 'half' route to make the flow decomposer logic happy |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1681 | for routeLink, path := range agent.deviceRoutes.Routes { |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 1682 | if agent.isNNIPort(routeLink.Egress) { |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1683 | routes = append(routes, route.Hop{}) // first hop is set to empty |
| 1684 | routes = append(routes, path[1]) |
| 1685 | return routes, nil |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 1686 | } |
| 1687 | } |
khenaidoo | 787224a | 2020-04-16 18:08:47 -0400 | [diff] [blame] | 1688 | return nil, fmt.Errorf("no upstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 1689 | } |
| 1690 | //treat it as if the output port is the first NNI of the OLT |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 1691 | var err error |
| 1692 | if egressPortNo, err = agent.getFirstNNIPort(); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1693 | logger.Warnw("no-nni-port", log.Fields{"error": err}) |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1694 | return nil, err |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 1695 | } |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 1696 | } |
| 1697 | //If ingress port is not specified (nil), it may be a wildcarded |
| 1698 | //route if egress port is OFPP_CONTROLLER or a nni logical port, |
| 1699 | //in which case we need to create a half-route where only the egress |
| 1700 | //hop is filled, the first hop is nil |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 1701 | if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) { |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 1702 | // We can use the 2nd hop of any upstream route, so just find the first upstream: |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1703 | for routeLink, path := range agent.deviceRoutes.Routes { |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 1704 | if agent.isNNIPort(routeLink.Egress) { |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1705 | routes = append(routes, route.Hop{}) // first hop is set to empty |
| 1706 | routes = append(routes, path[1]) |
| 1707 | return routes, nil |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 1708 | } |
| 1709 | } |
khenaidoo | 787224a | 2020-04-16 18:08:47 -0400 | [diff] [blame] | 1710 | return nil, fmt.Errorf("no upstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 1711 | } |
| 1712 | //If egress port is not specified (nil), we can also can return a "half" route |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1713 | if egressPortNo == 0 { |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1714 | for routeLink, path := range agent.deviceRoutes.Routes { |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1715 | if routeLink.Ingress == ingressPortNo { |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1716 | routes = append(routes, path[0]) |
| 1717 | routes = append(routes, route.Hop{}) |
| 1718 | return routes, nil |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 1719 | } |
| 1720 | } |
khenaidoo | 787224a | 2020-04-16 18:08:47 -0400 | [diff] [blame] | 1721 | return nil, fmt.Errorf("no downstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 1722 | } |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 1723 | // Return the pre-calculated route |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1724 | return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 1725 | } |
| 1726 | |
khenaidoo | 3d3b8c2 | 2019-05-22 18:10:39 -0400 | [diff] [blame] | 1727 | //GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and |
| 1728 | //returns their port numbers. This function is invoked only during flow decomposition where the lock on the logical |
| 1729 | //device is already held. Therefore it is safe to retrieve the logical device without lock. |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1730 | func (agent *LogicalAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 { |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 1731 | lPorts := make([]uint32, 0) |
| 1732 | var exclPort uint32 |
| 1733 | if len(excludePort) == 1 { |
| 1734 | exclPort = excludePort[0] |
| 1735 | } |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 1736 | lDevice := agent.getLogicalDeviceWithoutLock() |
| 1737 | for _, port := range lDevice.Ports { |
| 1738 | if port.OfpPort.PortNo != exclPort { |
| 1739 | lPorts = append(lPorts, port.OfpPort.PortNo) |
khenaidoo | 89b0e94 | 2018-10-21 21:11:33 -0400 | [diff] [blame] | 1740 | } |
| 1741 | } |
| 1742 | return lPorts |
| 1743 | } |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1744 | |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1745 | // GetDeviceRoutes returns device graph |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1746 | func (agent *LogicalAgent) GetDeviceRoutes() *route.DeviceRoutes { |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1747 | return agent.deviceRoutes |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1748 | } |
| 1749 | |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1750 | //rebuildRoutes rebuilds the device routes |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1751 | func (agent *LogicalAgent) buildRoutes(ctx context.Context) error { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1752 | logger.Debugf("building-routes", log.Fields{"logical-device-id": agent.logicalDeviceID}) |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1753 | if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil { |
| 1754 | return err |
| 1755 | } |
| 1756 | defer agent.requestQueue.RequestComplete() |
| 1757 | |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1758 | if agent.deviceRoutes == nil { |
Kent Hagerman | 45a13e4 | 2020-04-13 12:23:50 -0400 | [diff] [blame] | 1759 | agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.getDevice) |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 1760 | } |
| 1761 | // Get all the logical ports on that logical device |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 1762 | lDevice := agent.getLogicalDeviceWithoutLock() |
| 1763 | |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1764 | if err := agent.deviceRoutes.ComputeRoutes(ctx, lDevice.Ports); err != nil { |
| 1765 | return err |
| 1766 | } |
| 1767 | if err := agent.deviceRoutes.Print(); err != nil { |
| 1768 | return err |
| 1769 | } |
| 1770 | |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 1771 | return nil |
khenaidoo | 19d7b63 | 2018-10-30 10:49:50 -0400 | [diff] [blame] | 1772 | } |
| 1773 | |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1774 | //updateRoutes updates the device routes |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1775 | func (agent *LogicalAgent) updateRoutes(ctx context.Context, lp *voltha.LogicalPort) error { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1776 | logger.Debugw("updateRoutes", log.Fields{"logicalDeviceId": agent.logicalDeviceID}) |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1777 | if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil { |
| 1778 | return err |
| 1779 | } |
| 1780 | defer agent.requestQueue.RequestComplete() |
| 1781 | |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1782 | if agent.deviceRoutes == nil { |
Kent Hagerman | 45a13e4 | 2020-04-13 12:23:50 -0400 | [diff] [blame] | 1783 | agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.getDevice) |
khenaidoo | 910204f | 2019-04-08 17:56:40 -0400 | [diff] [blame] | 1784 | } |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1785 | if err := agent.deviceRoutes.AddPort(ctx, lp, agent.logicalDevice.Ports); err != nil { |
| 1786 | return err |
khenaidoo | 0a822f9 | 2019-05-08 15:15:57 -0400 | [diff] [blame] | 1787 | } |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1788 | if err := agent.deviceRoutes.Print(); err != nil { |
| 1789 | return err |
| 1790 | } |
| 1791 | return nil |
khenaidoo | 0a822f9 | 2019-05-08 15:15:57 -0400 | [diff] [blame] | 1792 | } |
| 1793 | |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1794 | // diff go over two lists of logical ports and return what's new, what's changed and what's removed. |
Kent Hagerman | 8ad2995 | 2020-04-21 11:48:02 -0400 | [diff] [blame] | 1795 | func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts map[string]*voltha.LogicalPort) { |
| 1796 | newPorts = make(map[string]*voltha.LogicalPort, len(newList)) |
| 1797 | changedPorts = make(map[string]*voltha.LogicalPort, len(oldList)) |
| 1798 | deletedPorts = make(map[string]*voltha.LogicalPort, len(oldList)) |
| 1799 | |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1800 | for _, n := range newList { |
Kent Hagerman | 8ad2995 | 2020-04-21 11:48:02 -0400 | [diff] [blame] | 1801 | newPorts[n.Id] = n |
| 1802 | } |
| 1803 | |
| 1804 | for _, o := range oldList { |
| 1805 | if n, have := newPorts[o.Id]; have { |
| 1806 | delete(newPorts, o.Id) // not new |
| 1807 | if !proto.Equal(n, o) { |
| 1808 | changedPorts[n.Id] = n // changed |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1809 | } |
Kent Hagerman | 8ad2995 | 2020-04-21 11:48:02 -0400 | [diff] [blame] | 1810 | } else { |
| 1811 | deletedPorts[o.Id] = o // deleted |
khenaidoo | 2bc4828 | 2019-07-16 18:13:46 -0400 | [diff] [blame] | 1812 | } |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1813 | } |
Kent Hagerman | 8ad2995 | 2020-04-21 11:48:02 -0400 | [diff] [blame] | 1814 | |
| 1815 | return newPorts, changedPorts, deletedPorts |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1816 | } |
| 1817 | |
Kent Hagerman | 8ad2995 | 2020-04-21 11:48:02 -0400 | [diff] [blame] | 1818 | // portUpdated is invoked when a port is updated on the logical device |
| 1819 | func (agent *LogicalAgent) portUpdated(prevPorts, currPorts []*voltha.LogicalPort) interface{} { |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1820 | // Get the difference between the two list |
Kent Hagerman | 8ad2995 | 2020-04-21 11:48:02 -0400 | [diff] [blame] | 1821 | newPorts, changedPorts, deletedPorts := diff(prevPorts, currPorts) |
| 1822 | |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1823 | // Send the port change events to the OF controller |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 1824 | for _, newP := range newPorts { |
Kent Hagerman | 45a13e4 | 2020-04-13 12:23:50 -0400 | [diff] [blame] | 1825 | go agent.ldeviceMgr.SendChangeEvent(agent.logicalDeviceID, |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 1826 | &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort}) |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1827 | } |
| 1828 | for _, change := range changedPorts { |
Kent Hagerman | 45a13e4 | 2020-04-13 12:23:50 -0400 | [diff] [blame] | 1829 | go agent.ldeviceMgr.SendChangeEvent(agent.logicalDeviceID, |
khenaidoo | 910204f | 2019-04-08 17:56:40 -0400 | [diff] [blame] | 1830 | &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort}) |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1831 | } |
| 1832 | for _, del := range deletedPorts { |
Kent Hagerman | 45a13e4 | 2020-04-13 12:23:50 -0400 | [diff] [blame] | 1833 | go agent.ldeviceMgr.SendChangeEvent(agent.logicalDeviceID, |
khenaidoo | 910204f | 2019-04-08 17:56:40 -0400 | [diff] [blame] | 1834 | &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort}) |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1835 | } |
| 1836 | |
| 1837 | return nil |
| 1838 | } |
| 1839 | |
khenaidoo | 8f47419 | 2019-04-03 17:20:44 -0400 | [diff] [blame] | 1840 | // addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been |
| 1841 | // added and an eror in case a valid error is encountered. If the port was successfully added it will return |
| 1842 | // (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid |
| 1843 | // scenario. This also applies to the case where the port was already added. |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1844 | func (agent *LogicalAgent) addNNILogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) (bool, error) { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1845 | logger.Debugw("addNNILogicalPort", log.Fields{"NNI": port}) |
Chaitrashree G S | 7849b32 | 2020-03-29 19:25:49 -0400 | [diff] [blame] | 1846 | |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1847 | if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil { |
| 1848 | return false, err |
| 1849 | } |
khenaidoo | 1ce37ad | 2019-03-24 22:07:24 -0400 | [diff] [blame] | 1850 | if agent.portExist(device, port) { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1851 | logger.Debugw("port-already-exist", log.Fields{"port": port}) |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1852 | agent.requestQueue.RequestComplete() |
khenaidoo | 8f47419 | 2019-04-03 17:20:44 -0400 | [diff] [blame] | 1853 | return false, nil |
khenaidoo | 1ce37ad | 2019-03-24 22:07:24 -0400 | [diff] [blame] | 1854 | } |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1855 | agent.requestQueue.RequestComplete() |
khenaidoo | 1ce37ad | 2019-03-24 22:07:24 -0400 | [diff] [blame] | 1856 | |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1857 | var portCap *ic.PortCapability |
| 1858 | var err error |
| 1859 | // First get the port capability |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 1860 | if portCap, err = agent.deviceMgr.getPortCapability(ctx, device.Id, port.PortNo); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1861 | logger.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err}) |
khenaidoo | 8f47419 | 2019-04-03 17:20:44 -0400 | [diff] [blame] | 1862 | return false, err |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1863 | } |
khenaidoo | 1ce37ad | 2019-03-24 22:07:24 -0400 | [diff] [blame] | 1864 | |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1865 | if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil { |
| 1866 | return false, err |
| 1867 | } |
| 1868 | |
| 1869 | defer agent.requestQueue.RequestComplete() |
khenaidoo | 1ce37ad | 2019-03-24 22:07:24 -0400 | [diff] [blame] | 1870 | // Double check again if this port has been already added since the getPortCapability could have taken a long time |
| 1871 | if agent.portExist(device, port) { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1872 | logger.Debugw("port-already-exist", log.Fields{"port": port}) |
khenaidoo | 8f47419 | 2019-04-03 17:20:44 -0400 | [diff] [blame] | 1873 | return false, nil |
khenaidoo | 1ce37ad | 2019-03-24 22:07:24 -0400 | [diff] [blame] | 1874 | } |
| 1875 | |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1876 | portCap.Port.RootPort = true |
| 1877 | lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort) |
| 1878 | lp.DeviceId = device.Id |
| 1879 | lp.Id = fmt.Sprintf("nni-%d", port.PortNo) |
| 1880 | lp.OfpPort.PortNo = port.PortNo |
| 1881 | lp.OfpPort.Name = lp.Id |
| 1882 | lp.DevicePortNo = port.PortNo |
| 1883 | |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 1884 | ld := agent.getLogicalDeviceWithoutLock() |
| 1885 | |
Kent Hagerman | d9cc2e9 | 2019-11-04 13:28:15 -0500 | [diff] [blame] | 1886 | clonedPorts := clonePorts(ld.Ports) |
| 1887 | if clonedPorts == nil { |
| 1888 | clonedPorts = make([]*voltha.LogicalPort, 0) |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1889 | } |
Kent Hagerman | d9cc2e9 | 2019-11-04 13:28:15 -0500 | [diff] [blame] | 1890 | clonedPorts = append(clonedPorts, lp) |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1891 | |
Kent Hagerman | d9cc2e9 | 2019-11-04 13:28:15 -0500 | [diff] [blame] | 1892 | if err = agent.updateLogicalDevicePortsWithoutLock(ctx, ld, clonedPorts); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1893 | logger.Errorw("error-updating-logical-device", log.Fields{"error": err}) |
khenaidoo | 8f47419 | 2019-04-03 17:20:44 -0400 | [diff] [blame] | 1894 | return false, err |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1895 | } |
khenaidoo | 910204f | 2019-04-08 17:56:40 -0400 | [diff] [blame] | 1896 | |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1897 | // Update the device routes with this new logical port |
khenaidoo | 910204f | 2019-04-08 17:56:40 -0400 | [diff] [blame] | 1898 | clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort) |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1899 | go func() { |
| 1900 | if err := agent.updateRoutes(context.Background(), clonedLP); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1901 | logger.Warnw("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "logical-port": lp.OfpPort.PortNo, "error": err}) |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1902 | } |
| 1903 | }() |
khenaidoo | 910204f | 2019-04-08 17:56:40 -0400 | [diff] [blame] | 1904 | |
khenaidoo | 8f47419 | 2019-04-03 17:20:44 -0400 | [diff] [blame] | 1905 | return true, nil |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1906 | } |
| 1907 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1908 | func (agent *LogicalAgent) portExist(device *voltha.Device, port *voltha.Port) bool { |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 1909 | ldevice := agent.getLogicalDeviceWithoutLock() |
| 1910 | for _, lPort := range ldevice.Ports { |
| 1911 | if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label { |
| 1912 | return true |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1913 | } |
| 1914 | } |
| 1915 | return false |
| 1916 | } |
| 1917 | |
khenaidoo | 8f47419 | 2019-04-03 17:20:44 -0400 | [diff] [blame] | 1918 | // addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been |
| 1919 | // added and an eror in case a valid error is encountered. If the port was successfully added it will return |
| 1920 | // (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid |
| 1921 | // scenario. This also applies to the case where the port was already added. |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1922 | func (agent *LogicalAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device, port *voltha.Port) (bool, error) { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1923 | logger.Debugw("addUNILogicalPort", log.Fields{"port": port}) |
khenaidoo | 8f47419 | 2019-04-03 17:20:44 -0400 | [diff] [blame] | 1924 | if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1925 | logger.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus}) |
khenaidoo | 8f47419 | 2019-04-03 17:20:44 -0400 | [diff] [blame] | 1926 | return false, nil |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1927 | } |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1928 | if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil { |
| 1929 | return false, err |
| 1930 | } |
| 1931 | |
khenaidoo | 1ce37ad | 2019-03-24 22:07:24 -0400 | [diff] [blame] | 1932 | if agent.portExist(childDevice, port) { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1933 | logger.Debugw("port-already-exist", log.Fields{"port": port}) |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1934 | agent.requestQueue.RequestComplete() |
khenaidoo | 8f47419 | 2019-04-03 17:20:44 -0400 | [diff] [blame] | 1935 | return false, nil |
khenaidoo | 1ce37ad | 2019-03-24 22:07:24 -0400 | [diff] [blame] | 1936 | } |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1937 | agent.requestQueue.RequestComplete() |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1938 | var portCap *ic.PortCapability |
| 1939 | var err error |
| 1940 | // First get the port capability |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 1941 | if portCap, err = agent.deviceMgr.getPortCapability(ctx, childDevice.Id, port.PortNo); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1942 | logger.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err}) |
khenaidoo | 8f47419 | 2019-04-03 17:20:44 -0400 | [diff] [blame] | 1943 | return false, err |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1944 | } |
khenaidoo | 442e7c7 | 2020-03-10 16:13:48 -0400 | [diff] [blame] | 1945 | if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil { |
| 1946 | return false, err |
| 1947 | } |
| 1948 | defer agent.requestQueue.RequestComplete() |
khenaidoo | 1ce37ad | 2019-03-24 22:07:24 -0400 | [diff] [blame] | 1949 | // Double check again if this port has been already added since the getPortCapability could have taken a long time |
| 1950 | if agent.portExist(childDevice, port) { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1951 | logger.Debugw("port-already-exist", log.Fields{"port": port}) |
khenaidoo | 8f47419 | 2019-04-03 17:20:44 -0400 | [diff] [blame] | 1952 | return false, nil |
khenaidoo | 1ce37ad | 2019-03-24 22:07:24 -0400 | [diff] [blame] | 1953 | } |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1954 | // Get stored logical device |
khenaidoo | 6e55d9e | 2019-12-12 18:26:26 -0500 | [diff] [blame] | 1955 | ldevice := agent.getLogicalDeviceWithoutLock() |
| 1956 | |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1957 | logger.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id}) |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1958 | portCap.Port.RootPort = false |
| 1959 | portCap.Port.Id = port.Label |
| 1960 | portCap.Port.OfpPort.PortNo = port.PortNo |
| 1961 | portCap.Port.DeviceId = childDevice.Id |
| 1962 | portCap.Port.DevicePortNo = port.PortNo |
Kent Hagerman | d9cc2e9 | 2019-11-04 13:28:15 -0500 | [diff] [blame] | 1963 | clonedPorts := clonePorts(ldevice.Ports) |
| 1964 | if clonedPorts == nil { |
| 1965 | clonedPorts = make([]*voltha.LogicalPort, 0) |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1966 | } |
Kent Hagerman | d9cc2e9 | 2019-11-04 13:28:15 -0500 | [diff] [blame] | 1967 | clonedPorts = append(clonedPorts, portCap.Port) |
| 1968 | if err := agent.updateLogicalDevicePortsWithoutLock(ctx, ldevice, clonedPorts); err != nil { |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1969 | return false, err |
| 1970 | } |
| 1971 | // Update the device graph with this new logical port |
| 1972 | clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort) |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 1973 | |
| 1974 | go func() { |
| 1975 | if err := agent.updateRoutes(context.Background(), clonedLP); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1976 | 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] | 1977 | } |
| 1978 | }() |
| 1979 | |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 1980 | return true, nil |
khenaidoo | fc1314d | 2019-03-14 09:34:21 -0400 | [diff] [blame] | 1981 | } |
| 1982 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1983 | func (agent *LogicalAgent) packetOut(ctx context.Context, packet *ofp.OfpPacketOut) { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1984 | logger.Debugw("packet-out", log.Fields{ |
Matteo Scandolo | 360605d | 2019-11-05 18:29:17 -0800 | [diff] [blame] | 1985 | "packet": hex.EncodeToString(packet.Data), |
| 1986 | "inPort": packet.GetInPort(), |
| 1987 | }) |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 1988 | outPort := fu.GetPacketOutPort(packet) |
khenaidoo | fdbad6e | 2018-11-06 22:26:38 -0500 | [diff] [blame] | 1989 | //frame := packet.GetData() |
| 1990 | //TODO: Use a channel between the logical agent and the device agent |
npujar | 467fe75 | 2020-01-16 20:17:45 +0530 | [diff] [blame] | 1991 | if err := agent.deviceMgr.packetOut(ctx, agent.rootDeviceID, outPort, packet); err != nil { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1992 | logger.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceID}) |
khenaidoo | ca30132 | 2019-01-09 23:06:32 -0500 | [diff] [blame] | 1993 | } |
khenaidoo | fdbad6e | 2018-11-06 22:26:38 -0500 | [diff] [blame] | 1994 | } |
| 1995 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 1996 | func (agent *LogicalAgent) packetIn(port uint32, transactionID string, packet []byte) { |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 1997 | logger.Debugw("packet-in", log.Fields{ |
Matteo Scandolo | 360605d | 2019-11-05 18:29:17 -0800 | [diff] [blame] | 1998 | "port": port, |
| 1999 | "packet": hex.EncodeToString(packet), |
npujar | 1d86a52 | 2019-11-14 17:11:16 +0530 | [diff] [blame] | 2000 | "transactionId": transactionID, |
Matteo Scandolo | 360605d | 2019-11-05 18:29:17 -0800 | [diff] [blame] | 2001 | }) |
khenaidoo | 68c930b | 2019-05-13 11:46:51 -0400 | [diff] [blame] | 2002 | packetIn := fu.MkPacketIn(port, packet) |
Kent Hagerman | 45a13e4 | 2020-04-13 12:23:50 -0400 | [diff] [blame] | 2003 | agent.ldeviceMgr.SendPacketIn(agent.logicalDeviceID, transactionID, packetIn) |
Girish Kumar | f56a468 | 2020-03-20 20:07:46 +0000 | [diff] [blame] | 2004 | logger.Debugw("sending-packet-in", log.Fields{"packet": hex.EncodeToString(packetIn.Data)}) |
khenaidoo | fdbad6e | 2018-11-06 22:26:38 -0500 | [diff] [blame] | 2005 | } |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 2006 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 2007 | func (agent *LogicalAgent) addLogicalPortToMap(portNo uint32, nniPort bool) { |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 2008 | agent.lockLogicalPortsNo.Lock() |
| 2009 | defer agent.lockLogicalPortsNo.Unlock() |
| 2010 | if exist := agent.logicalPortsNo[portNo]; !exist { |
| 2011 | agent.logicalPortsNo[portNo] = nniPort |
| 2012 | } |
| 2013 | } |
| 2014 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 2015 | func (agent *LogicalAgent) deleteLogicalPortsFromMap(portsNo []uint32) { |
khenaidoo | 820197c | 2020-02-13 16:35:33 -0500 | [diff] [blame] | 2016 | agent.lockLogicalPortsNo.Lock() |
| 2017 | defer agent.lockLogicalPortsNo.Unlock() |
| 2018 | for _, pNo := range portsNo { |
| 2019 | delete(agent.logicalPortsNo, pNo) |
| 2020 | } |
| 2021 | } |
| 2022 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 2023 | func (agent *LogicalAgent) addLogicalPortsToMap(lps []*voltha.LogicalPort) { |
khenaidoo | 3d3b8c2 | 2019-05-22 18:10:39 -0400 | [diff] [blame] | 2024 | agent.lockLogicalPortsNo.Lock() |
| 2025 | defer agent.lockLogicalPortsNo.Unlock() |
| 2026 | for _, lp := range lps { |
| 2027 | if exist := agent.logicalPortsNo[lp.DevicePortNo]; !exist { |
| 2028 | agent.logicalPortsNo[lp.DevicePortNo] = lp.RootPort |
| 2029 | } |
| 2030 | } |
| 2031 | } |
| 2032 | |
Mahir Gunyel | addb66a | 2020-04-29 18:08:50 -0700 | [diff] [blame^] | 2033 | func (agent *LogicalAgent) loadFlows(ctx context.Context) { |
| 2034 | agent.flowLock.Lock() |
| 2035 | defer agent.flowLock.Unlock() |
| 2036 | |
| 2037 | var flowList []*ofp.OfpFlowStats |
| 2038 | if err := agent.clusterDataProxy.List(ctx, "logical_flows/"+agent.logicalDeviceID, &flowList); err != nil { |
| 2039 | logger.Errorw("Failed-to-list-logicalflows-from-cluster-data-proxy", log.Fields{"error": err}) |
| 2040 | return |
| 2041 | } |
| 2042 | for _, flow := range flowList { |
| 2043 | if flow != nil { |
| 2044 | flowsChunk := FlowChunk{ |
| 2045 | flow: flow, |
| 2046 | } |
| 2047 | agent.flows[flow.Id] = &flowsChunk |
| 2048 | } |
| 2049 | } |
| 2050 | } |
| 2051 | |
| 2052 | func (agent *LogicalAgent) loadMeters(ctx context.Context) { |
| 2053 | agent.meterLock.Lock() |
| 2054 | defer agent.meterLock.Unlock() |
| 2055 | |
| 2056 | var meters []*ofp.OfpMeterEntry |
| 2057 | if err := agent.clusterDataProxy.List(ctx, "meters/"+agent.logicalDeviceID, &meters); err != nil { |
| 2058 | logger.Errorw("Failed-to-list-meters-from-proxy", log.Fields{"error": err}) |
| 2059 | return |
| 2060 | } |
| 2061 | for _, meter := range meters { |
| 2062 | if meter.Config != nil { |
| 2063 | meterChunk := MeterChunk{ |
| 2064 | meter: meter, |
| 2065 | } |
| 2066 | agent.meters[meter.Config.MeterId] = &meterChunk |
| 2067 | } |
| 2068 | } |
| 2069 | } |
| 2070 | |
| 2071 | func (agent *LogicalAgent) loadGroups(ctx context.Context) { |
| 2072 | agent.groupLock.Lock() |
| 2073 | defer agent.groupLock.Unlock() |
| 2074 | |
| 2075 | var groups []*ofp.OfpGroupEntry |
| 2076 | if err := agent.clusterDataProxy.List(ctx, "groups/"+agent.logicalDeviceID, &groups); err != nil { |
| 2077 | logger.Errorw("Failed-to-list-groups-from-proxy", log.Fields{"error": err}) |
| 2078 | return |
| 2079 | } |
| 2080 | for _, group := range groups { |
| 2081 | if group.Desc != nil { |
| 2082 | groupChunk := GroupChunk{ |
| 2083 | group: group, |
| 2084 | } |
| 2085 | agent.groups[group.Desc.GroupId] = &groupChunk |
| 2086 | } |
| 2087 | } |
| 2088 | logger.Infow("Groups-are-loaded-into-the-cache-from-store", log.Fields{"logicalDeviceID": agent.logicalDeviceID}) |
| 2089 | } |
| 2090 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 2091 | func (agent *LogicalAgent) isNNIPort(portNo uint32) bool { |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 2092 | agent.lockLogicalPortsNo.RLock() |
| 2093 | defer agent.lockLogicalPortsNo.RUnlock() |
| 2094 | if exist := agent.logicalPortsNo[portNo]; exist { |
| 2095 | return agent.logicalPortsNo[portNo] |
| 2096 | } |
| 2097 | return false |
| 2098 | } |
| 2099 | |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 2100 | func (agent *LogicalAgent) getFirstNNIPort() (uint32, error) { |
khenaidoo | 2c6a099 | 2019-04-29 13:46:56 -0400 | [diff] [blame] | 2101 | agent.lockLogicalPortsNo.RLock() |
| 2102 | defer agent.lockLogicalPortsNo.RUnlock() |
| 2103 | for portNo, nni := range agent.logicalPortsNo { |
| 2104 | if nni { |
| 2105 | return portNo, nil |
| 2106 | } |
| 2107 | } |
| 2108 | return 0, status.Error(codes.NotFound, "No NNI port found") |
| 2109 | } |
Esin Karaman | 09959ae | 2019-11-29 13:59:58 +0000 | [diff] [blame] | 2110 | |
| 2111 | //GetNNIPorts returns NNI ports. |
Kent Hagerman | 2b21604 | 2020-04-03 18:28:56 -0400 | [diff] [blame] | 2112 | func (agent *LogicalAgent) GetNNIPorts() []uint32 { |
Esin Karaman | 09959ae | 2019-11-29 13:59:58 +0000 | [diff] [blame] | 2113 | agent.lockLogicalPortsNo.RLock() |
| 2114 | defer agent.lockLogicalPortsNo.RUnlock() |
| 2115 | nniPorts := make([]uint32, 0) |
| 2116 | for portNo, nni := range agent.logicalPortsNo { |
| 2117 | if nni { |
| 2118 | nniPorts = append(nniPorts, portNo) |
| 2119 | } |
| 2120 | } |
| 2121 | return nniPorts |
| 2122 | } |