Esempio n. 1
0
void BcmRoute::programLpmRoute(opennsl_if_t egressId,
    const RouteNextHopEntry& fwd) {
  opennsl_l3_route_t rt;
  initL3RouteT(&rt);
  rt.l3a_intf = egressId;
  if (fwd.getNextHopSet().size() > 1) {         // multipath
    rt.l3a_flags |= OPENNSL_L3_MULTIPATH;
  }

  bool addRoute = false;
  const auto warmBootCache = hw_->getWarmBootCache();
  auto vrfAndPfx2RouteCitr = warmBootCache->findRoute(vrf_, prefix_, len_);
  if (vrfAndPfx2RouteCitr != warmBootCache->vrfAndPrefix2Route_end()) {
    // Lambda to compare if the routes are equivalent and thus we need to
    // do nothing
    auto equivalent =
      [=] (const opennsl_l3_route_t& newRoute,
           const opennsl_l3_route_t& existingRoute) {
      // Compare flags (primarily MULTIPATH vs non MULTIPATH
      // and egress id.
      return existingRoute.l3a_flags == newRoute.l3a_flags &&
      existingRoute.l3a_intf == newRoute.l3a_intf;
    };
    if (!equivalent(rt, vrfAndPfx2RouteCitr->second)) {
      VLOG (3) << "Updating route for : " << prefix_ << "/"
        << static_cast<int>(len_) << " in vrf : " << vrf_;
      // This is a change
      rt.l3a_flags |= OPENNSL_L3_REPLACE;
      addRoute = true;
    } else {
      VLOG(3) << " Route for : " << prefix_ << "/" << static_cast<int>(len_)
        << " in vrf : " << vrf_ << " already exists";
    }
  } else {
    addRoute = true;
  }
  if (addRoute) {
    if (vrfAndPfx2RouteCitr == warmBootCache->vrfAndPrefix2Route_end()) {
      VLOG (3) << "Adding route for : " << prefix_ << "/"
        << static_cast<int>(len_) << " in vrf : " << vrf_;
    }
    if (added_) {
      rt.l3a_flags |= OPENNSL_L3_REPLACE;
    }
    auto rc = opennsl_l3_route_add(hw_->getUnit(), &rt);
    bcmCheckError(rc, "failed to create a route entry for ", prefix_, "/",
        static_cast<int>(len_), " @ ", fwd, " @egress ", egressId);
    VLOG(3) << "created a route entry for " << prefix_.str() << "/"
      << static_cast<int>(len_) << " @egress " << egressId
      << " with " << fwd;
  }
  if (vrfAndPfx2RouteCitr != warmBootCache->vrfAndPrefix2Route_end()) {
    warmBootCache->programmed(vrfAndPfx2RouteCitr);
  }
}
sai_status_t
brcm_sai_create_route(_In_ const sai_unicast_route_entry_t* unicast_route_entry,
                      _In_ sai_uint32_t attr_count,
                      _In_ const sai_attribute_t *attr_list)
{
    int i;
    sai_status_t rv;
    opennsl_if_t l3_if_id = -1;
    opennsl_l3_route_t l3_rt;
    bool trap = false,  drop = false, copy_to_cpu = false;
    sai_uint32_t vr_id;

    BRCM_SAI_FUNCTION_ENTER(SAI_API_ROUTE);
    BRCM_SAI_SWITCH_INIT_CHECK;
    BRCM_SAI_OBJ_CREATE_PARAM_CHK(unicast_route_entry);

    opennsl_l3_route_t_init(&l3_rt);
    for (i=0; i<attr_count; i++)
    {
        switch (attr_list[i].id)
        {
            case SAI_ROUTE_ATTR_NEXT_HOP_ID:
                l3_if_id = BRCM_SAI_GET_OBJ_VAL(opennsl_if_t,
                                                BRCM_SAI_ATTR_LIST_OBJ(i));
                if (SAI_OBJECT_TYPE_NEXT_HOP_GROUP ==
                    BRCM_SAI_GET_OBJ_TYPE(BRCM_SAI_ATTR_LIST_OBJ(i)))
                {
                    l3_rt.l3a_flags |= OPENNSL_L3_MULTIPATH;
                }
                break;
            case SAI_ROUTE_ATTR_PACKET_ACTION:
                if (SAI_PACKET_ACTION_LOG == attr_list[i].value.u32)
                {
                    copy_to_cpu = true;
                }
                else if (SAI_PACKET_ACTION_TRAP == attr_list[i].value.u32)
                {
                    trap = true;
                    l3_rt.l3a_flags |= OPENNSL_L3_DEFIP_CPU;
                }
                else if (SAI_PACKET_ACTION_DROP == attr_list[i].value.u32)
                {
                    drop = true;
                    l3_rt.l3a_flags |= OPENNSL_L3_DST_DISCARD;
                }
                else
                {
                    BRCM_SAI_LOG_ROUTE(SAI_LOG_ERROR, "Bad attribute passed\n");
                    return SAI_STATUS_INVALID_PARAMETER;
                }
                break;
            default:
                BRCM_SAI_LOG_ROUTE(SAI_LOG_ERROR, "Unimplemented attribute passed\n");
                break;
        }
    }
    if (-1 == l3_if_id && FALSE == trap && FALSE == drop)
    {
        BRCM_SAI_LOG_ROUTE(SAI_LOG_ERROR, "Missing routing info.\n");
                           return SAI_STATUS_INVALID_PARAMETER;
    }
    if (SAI_IP_ADDR_FAMILY_IPV4 == unicast_route_entry->destination.addr_family)
    {
        l3_rt.l3a_ip_mask = ntohl(unicast_route_entry->destination.mask.ip4);
        l3_rt.l3a_subnet = ntohl(unicast_route_entry->destination.addr.ip4 &
                                 unicast_route_entry->destination.mask.ip4);
    }
    else if (SAI_IP_ADDR_FAMILY_IPV6 ==
             unicast_route_entry->destination.addr_family)
    {
        memcpy(l3_rt.l3a_ip6_net, unicast_route_entry->destination.addr.ip6,
               sizeof(l3_rt.l3a_ip6_net));
        memcpy(l3_rt.l3a_ip6_mask, unicast_route_entry->destination.mask.ip6,
               sizeof(l3_rt.l3a_ip6_mask));
    }
    else
    {
        BRCM_SAI_LOG_ROUTE(SAI_LOG_ERROR, "Bad address family passed\n");
        return SAI_STATUS_INVALID_PARAMETER;
    }
    vr_id = BRCM_SAI_GET_OBJ_VAL(sai_uint32_t, unicast_route_entry->vr_id);
    if (false == _brcm_sai_vr_id_valid(vr_id))
    {
        BRCM_SAI_LOG_ROUTE(SAI_LOG_ERROR,
                           "Invalid VR id passed during route create %d\n",
                           vr_id);
        return SAI_STATUS_INVALID_PARAMETER;
    }

    l3_rt.l3a_vrf = vr_id;
    if (trap)
    {
        l3_rt.l3a_intf = _brcm_sai_vrf_if_get(l3_rt.l3a_vrf);
    }
    else if (drop)
    {
        l3_rt.l3a_intf = _brcm_sai_vrf_drop_if_get(l3_rt.l3a_vrf);
    }
    else
    {
        l3_rt.l3a_intf = l3_if_id;

        if (TRUE == copy_to_cpu)
        {
          opennsl_l3_egress_t l3_egr;
          uint32 flags = OPENNSL_L3_REPLACE | OPENNSL_L3_WITH_ID;

          rv = opennsl_l3_egress_get(0, l3_if_id, &l3_egr);
          BRCM_SAI_API_CHK(SAI_API_ROUTE, "L3 egress get", rv);

          l3_egr.flags |= OPENNSL_L3_COPY_TO_CPU;
          rv = opennsl_l3_egress_create(0, flags, &l3_egr, &l3_if_id);
          BRCM_SAI_API_CHK(SAI_API_ROUTE, "L3 egress create w/ replace", rv);
        }
    }
    BRCM_SAI_LOG_ROUTE(SAI_LOG_DEBUG,
                       "Add route vrf: %d, egr %s id: %d mask 0x%x, subnet 0x%x\n",
                       l3_rt.l3a_vrf,
                       !(l3_rt.l3a_flags & OPENNSL_L3_MULTIPATH) ? "nh" : "nhg",
                       l3_rt.l3a_intf,
                       l3_rt.l3a_ip_mask,
                       l3_rt.l3a_subnet );
    rv = opennsl_l3_route_add(0, &l3_rt);
    BRCM_SAI_API_CHK(SAI_API_ROUTE, "L3 route add", rv);

    BRCM_SAI_FUNCTION_EXIT(SAI_API_ROUTE);

    return rv;
}
/*
################################################################################
#                               Internal functions                             #
################################################################################
*/
sai_status_t
_brcm_sai_update_route(const sai_unicast_route_entry_t* unicast_route_entry,
                       sai_uint32_t attr_count,
                       const sai_attribute_t *attr_list)
{
    int i;
    sai_status_t rv;
    opennsl_if_t l3_if_id = -1;
    opennsl_l3_route_t l3_rt;
    bool trap = false, drop = false;
    sai_uint32_t vr_id;

    BRCM_SAI_FUNCTION_ENTER(SAI_API_ROUTE);
    BRCM_SAI_SWITCH_INIT_CHECK;

    if ((NULL == unicast_route_entry) || (NULL == attr_list) || (0 == attr_count))
    {
        BRCM_SAI_LOG_ROUTE(SAI_LOG_ERROR, "NULL params passed\n");
        return SAI_STATUS_INVALID_PARAMETER;
    }
    opennsl_l3_route_t_init(&l3_rt);
    for (i=0; i<attr_count; i++)
    {
        switch (attr_list[i].id)
        {
            case SAI_ROUTE_ATTR_NEXT_HOP_ID:
                l3_if_id = attr_list[i].value.u32;
                if (SAI_OBJECT_TYPE_NEXT_HOP_GROUP ==
                    BRCM_SAI_GET_OBJ_TYPE(BRCM_SAI_ATTR_LIST_OBJ(i)))
                {
                    l3_rt.l3a_flags |= OPENNSL_L3_MULTIPATH;
                }
                break;
            case SAI_ROUTE_ATTR_PACKET_ACTION:
                if (SAI_PACKET_ACTION_LOG == attr_list[i].value.u32)
                {
                    l3_rt.l3a_flags |= OPENNSL_L3_COPY_TO_CPU;
                }
                else if (SAI_PACKET_ACTION_TRAP == attr_list[i].value.u32)
                {
                    trap = true;
                    l3_rt.l3a_flags |= OPENNSL_L3_DEFIP_CPU;
                }
                else if (SAI_PACKET_ACTION_DROP == attr_list[i].value.u32)
                {
                    drop = true;
                    l3_rt.l3a_flags |= OPENNSL_L3_DST_DISCARD;
                }
                else
                {
                    BRCM_SAI_LOG_ROUTE(SAI_LOG_ERROR, "Bad attribute passed\n");
                    return SAI_STATUS_INVALID_PARAMETER;
                }
            default:
                BRCM_SAI_LOG_ROUTE(SAI_LOG_INFO, "Un-supported attribute %d passed\n",
                                   attr_list[i].id);
                break;
        }
    }
    if (-1 == l3_if_id && FALSE == trap && FALSE == drop)
    {
        BRCM_SAI_LOG_ROUTE(SAI_LOG_ERROR, "Missing routing info.\n");
                           return SAI_STATUS_INVALID_PARAMETER;
    }
    if (SAI_IP_ADDR_FAMILY_IPV4 == unicast_route_entry->destination.addr_family)
    {
        l3_rt.l3a_ip_mask = ntohl(unicast_route_entry->destination.mask.ip4);
        l3_rt.l3a_subnet = ntohl(unicast_route_entry->destination.addr.ip4 &
                                 unicast_route_entry->destination.mask.ip4);
    }
    else if (SAI_IP_ADDR_FAMILY_IPV6 ==
             unicast_route_entry->destination.addr_family)
    {
        memcpy(l3_rt.l3a_ip6_net, unicast_route_entry->destination.addr.ip6,
               sizeof(l3_rt.l3a_ip6_net));
        memcpy(l3_rt.l3a_ip6_mask, unicast_route_entry->destination.mask.ip6,
               sizeof(l3_rt.l3a_ip6_mask));
    }
    else
    {
        return SAI_STATUS_INVALID_PARAMETER;
    }
    vr_id = BRCM_SAI_GET_OBJ_VAL(sai_uint32_t, unicast_route_entry->vr_id);
    if (false == _brcm_sai_vr_id_valid(vr_id))
    {
        BRCM_SAI_LOG_ROUTE(SAI_LOG_ERROR,
                           "Invalid VR id passed during route create %d\n",
                           vr_id);
        return SAI_STATUS_INVALID_PARAMETER;
    }

    l3_rt.l3a_vrf = vr_id;
    if (trap)
    {
        l3_rt.l3a_intf = _brcm_sai_vrf_if_get(l3_rt.l3a_vrf);
    }
    else if (drop)
    {
        l3_rt.l3a_intf = _brcm_sai_vrf_drop_if_get(l3_rt.l3a_vrf);
    }
    else
    {
        l3_rt.l3a_intf = l3_if_id;
    }

    l3_rt.l3a_flags |= OPENNSL_L3_REPLACE;

    BRCM_SAI_LOG_ROUTE(SAI_LOG_DEBUG, "Update route vrf: %d, egr %s id: %d\n",
                       l3_rt.l3a_vrf,
                       !(l3_rt.l3a_flags & OPENNSL_L3_MULTIPATH) ? "nh" : "nhg",
                       l3_rt.l3a_intf);
    rv = opennsl_l3_route_add(0, &l3_rt);
    BRCM_SAI_API_CHK(SAI_API_ROUTE, "L3 route add", rv);

    BRCM_SAI_FUNCTION_EXIT(SAI_API_ROUTE);

    return rv;
}