blob: 333efa8d6447b4adfceefdc93c3249d036684423 [file] [log] [blame]
/*
* Copyright 2018-present Open Networking Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package device
import (
"context"
"fmt"
"github.com/opencord/voltha-go/rw_core/route"
"github.com/opencord/voltha-lib-go/v7/pkg/log"
ofp "github.com/opencord/voltha-protos/v5/go/openflow_13"
"github.com/opencord/voltha-protos/v5/go/voltha"
)
// GetRoute returns a route
func (agent *LogicalAgent) GetRoute(ctx context.Context, ingressPortNo uint32, egressPortNo uint32) ([]route.Hop, error) {
logger.Debugw(ctx, "getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
routes := make([]route.Hop, 0)
// Note: A port value of 0 is equivalent to a nil port
// Controller-bound flow
if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
logger.Debugw(ctx, "controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo})
if agent.isNNIPort(ingressPortNo) {
//This is a trap on the NNI Port
if agent.deviceRoutes.IsRoutesEmpty() {
// If there are no routes set (usually when the logical device has only NNI port(s), then just return an
// route with same IngressHop and EgressHop
hop := route.Hop{DeviceID: agent.rootDeviceID, Ingress: ingressPortNo, Egress: ingressPortNo}
routes = append(routes, hop)
routes = append(routes, hop)
return routes, nil
}
// Return a 'half' route to make the flow decomposer logic happy
routes, err := agent.deviceRoutes.GetHalfRoute(true, 0, 0)
if err != nil {
return nil, fmt.Errorf("no upstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute)
}
return routes, nil
}
// Treat it as if the output port is the first NNI of the OLT
var err error
if egressPortNo, err = agent.getAnyNNIPort(); err != nil {
logger.Warnw(ctx, "no-nni-port", log.Fields{"error": err})
return nil, err
}
}
//If ingress port is not specified (nil), it may be a wildcarded route if egress port is OFPP_CONTROLLER or a nni
// logical port, in which case we need to create a half-route where only the egress hop is filled, the first hop is nil
if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) {
routes, err := agent.deviceRoutes.GetHalfRoute(true, ingressPortNo, egressPortNo)
if err != nil {
return nil, fmt.Errorf("no upstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute)
}
return routes, nil
}
//If egress port is not specified (nil), we can also can return a "half" route
if egressPortNo == 0 {
routes, err := agent.deviceRoutes.GetHalfRoute(false, ingressPortNo, egressPortNo)
if err != nil {
return nil, fmt.Errorf("no downstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute)
}
return routes, nil
}
// Return the pre-calculated route
return agent.deviceRoutes.GetRoute(ctx, ingressPortNo, egressPortNo)
}
// GetDeviceRoutes returns device graph
func (agent *LogicalAgent) GetDeviceRoutes() *route.DeviceRoutes {
return agent.deviceRoutes
}
//rebuildRoutes rebuilds the device routes
func (agent *LogicalAgent) buildRoutes(ctx context.Context) error {
logger.Debugf(ctx, "building-routes", log.Fields{"logical-device-id": agent.logicalDeviceID})
if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
return err
}
defer agent.requestQueue.RequestComplete()
if err := agent.deviceRoutes.ComputeRoutes(ctx, agent.listLogicalDevicePorts(ctx)); err != nil {
return err
}
if err := agent.deviceRoutes.Print(ctx); err != nil {
return err
}
return nil
}
func (agent *LogicalAgent) removeRoutes(ctx context.Context) error {
if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
return err
}
defer agent.requestQueue.RequestComplete()
agent.deviceRoutes.RemoveRoutes()
return nil
}
//updateRoutes updates the device routes
func (agent *LogicalAgent) updateRoutes(ctx context.Context, deviceID string, devicePorts map[uint32]*voltha.Port, lp *voltha.LogicalPort, lps map[uint32]*voltha.LogicalPort) error {
logger.Debugw(ctx, "updateRoutes", log.Fields{"logical-device-id": agent.logicalDeviceID, "device-id": deviceID, "port:": lp})
if err := agent.deviceRoutes.AddPort(ctx, lp, deviceID, devicePorts, lps); err != nil {
return err
}
if err := agent.deviceRoutes.Print(ctx); err != nil {
return err
}
return nil
}
//updateAllRoutes updates the device routes using all the logical ports on that device
func (agent *LogicalAgent) updateAllRoutes(ctx context.Context, deviceID string, devicePorts map[uint32]*voltha.Port) error {
logger.Debugw(ctx, "updateAllRoutes", log.Fields{"logical-device-id": agent.logicalDeviceID, "device-id": deviceID, "ports-count": len(devicePorts)})
if err := agent.deviceRoutes.AddAllPorts(ctx, deviceID, devicePorts, agent.listLogicalDevicePorts(ctx)); err != nil {
return err
}
if err := agent.deviceRoutes.Print(ctx); err != nil {
return err
}
return nil
}