Esempio n. 1
0
void neigh_create(switchlink_handle_t vrf_h,
                  switchlink_ip_addr_t *ipaddr,
                  switchlink_mac_addr_t mac_addr,
                  switchlink_handle_t intf_h) {
  switchlink_db_status_t status;
  switchlink_db_neigh_info_t neigh_info;

  if ((ipaddr->family == AF_INET6) &&
      IN6_IS_ADDR_MULTICAST(&(ipaddr->ip.v6addr))) {
    return;
  }

  memset(&neigh_info, 0, sizeof(switchlink_db_neigh_info_t));
  neigh_info.vrf_h = vrf_h;
  neigh_info.intf_h = intf_h;
  memcpy(&(neigh_info.ip_addr), ipaddr, sizeof(switchlink_ip_addr_t));

  status = switchlink_db_neighbor_get_info(&neigh_info);
  if (status == SWITCHLINK_DB_STATUS_SUCCESS) {
    if (memcmp(neigh_info.mac_addr, mac_addr, sizeof(switchlink_mac_addr_t)) ==
        0) {
      // no change
      return;
    }

    // update, currently handled as a delete followed by add
    neigh_delete(vrf_h, ipaddr, intf_h);
  }

  memcpy(neigh_info.mac_addr, mac_addr, sizeof(switchlink_mac_addr_t));
  if (switchlink_nexthop_create(&neigh_info) == -1) {
    return;
  }
  if (switchlink_neighbor_create(&neigh_info) == -1) {
    switchlink_nexthop_delete(&neigh_info);
    return;
  }
  switchlink_db_neighbor_add(&neigh_info);

  // add a host route
  route_create(g_default_vrf_h, ipaddr, ipaddr, 0, intf_h);
}
static void
neigh_delete(switchlink_handle_t vrf_h, switchlink_ip_addr_t *ipaddr,
             switchlink_handle_t intf_h) {
    switchlink_db_neigh_info_t neigh_info;
    switchlink_db_status_t status;

    memset(&neigh_info, 0, sizeof(switchlink_db_neigh_info_t));
    neigh_info.vrf_h = vrf_h;
    neigh_info.intf_h = intf_h;
    memcpy(&(neigh_info.ip_addr), ipaddr, sizeof(switchlink_ip_addr_t));
    status = switchlink_db_neighbor_get_info(&neigh_info);
    if (status != SWITCHLINK_DB_STATUS_SUCCESS) {
        return;
    }

    switchlink_neighbor_delete(&neigh_info);
    switchlink_nexthop_delete(&neigh_info);
    switchlink_db_neighbor_delete(&neigh_info);

    // delete the host route
    route_delete(g_default_vrf_h, ipaddr);
}
void
route_create(switchlink_handle_t vrf_h, switchlink_ip_addr_t *dst,
             switchlink_ip_addr_t *gateway, switchlink_handle_t ecmp_h,
             switchlink_handle_t intf_h) {
    if (!dst || (!gateway && !ecmp_h)) {
        if (ecmp_h) {
            ecmp_delete(ecmp_h);
        }
        return;
    }

    bool ecmp_valid = false;
    switchlink_handle_t nhop_h = 0;
    if (!ecmp_h) {
        switchlink_db_neigh_info_t neigh_info;
        memset(&neigh_info, 0, sizeof(switchlink_db_neigh_info_t));
        memcpy(&(neigh_info.ip_addr), gateway, sizeof(switchlink_ip_addr_t));
        neigh_info.intf_h = intf_h;
        neigh_info.vrf_h = vrf_h;
        switchlink_db_status_t status;
        status = switchlink_db_neighbor_get_info(&neigh_info);
        if (status == SWITCHLINK_DB_STATUS_SUCCESS) {
            nhop_h = neigh_info.nhop_h;
        } else {
            nhop_h = g_cpu_rx_nhop_h;
        }
        ecmp_valid = false;
    } else {
        ecmp_valid = true;
        nhop_h = ecmp_h;
    }

    // get the route from the db (if it already exists)
    switchlink_db_route_info_t route_info;
    memset(&route_info, 0, sizeof(switchlink_db_route_info_t));
    route_info.vrf_h = vrf_h;
    memcpy(&(route_info.ip_addr), dst, sizeof(switchlink_ip_addr_t));
    switchlink_db_status_t status = switchlink_db_route_get_info(&route_info);
    if (status == SWITCHLINK_DB_STATUS_SUCCESS) {
        if ((route_info.ecmp == ecmp_valid) && (route_info.nhop_h == nhop_h)) {
            // no change
            return;
        }
        // nexthop has change, delete the current route
        route_delete(vrf_h, dst);
    }

    memset(&route_info, 0, sizeof(switchlink_db_route_info_t));
    route_info.vrf_h = vrf_h;
    memcpy(&(route_info.ip_addr), dst, sizeof(switchlink_ip_addr_t));
    route_info.ecmp = ecmp_valid;
    route_info.nhop_h = nhop_h;

    // add the route
    if (switchlink_route_create(&route_info) == -1) {
        if (route_info.ecmp) {
            ecmp_delete(route_info.nhop_h);
        }
        return;
    }

    // add the route to the db
    if (switchlink_db_route_add(&route_info) == SWITCHLINK_DB_STATUS_SUCCESS) {
        if (route_info.ecmp) {
            switchlink_db_ecmp_ref_inc(route_info.nhop_h);
        }
    }
}
static switchlink_handle_t
process_ecmp(uint8_t family, struct nlattr *attr, switchlink_handle_t vrf_h) {
    switchlink_db_status_t status;

    if ((family != AF_INET) && (family != AF_INET6)) {
        return 0;
    }

    switchlink_db_ecmp_info_t ecmp_info;
    memset(&ecmp_info, 0, sizeof(switchlink_db_ecmp_info_t));

    struct rtnexthop *rnh = (struct rtnexthop *)nla_data(attr);
    int attrlen = nla_len(attr);
    while (RTNH_OK(rnh, attrlen)) {
        struct rtattr *rta = RTNH_DATA(rnh);
        if (rta->rta_type == RTA_GATEWAY) {
            switchlink_ip_addr_t gateway;
            memset(&gateway, 0, sizeof(switchlink_ip_addr_t));
            gateway.family = family;
            if (family == AF_INET) {
                gateway.ip.v4addr.s_addr = ntohl(*((uint32_t *)RTA_DATA(rta)));
                gateway.prefix_len = 32;
            } else {
                gateway.prefix_len = 128;
            }

            switchlink_db_interface_info_t ifinfo;
            memset(&ifinfo, 0, sizeof(switchlink_db_interface_info_t));
            status = switchlink_db_interface_get_info(rnh->rtnh_ifindex,
                                                      &ifinfo);
            if (status == SWITCHLINK_DB_STATUS_SUCCESS) {
                switchlink_db_neigh_info_t neigh_info;
                memset(&neigh_info, 0, sizeof(switchlink_db_neigh_info_t));
                memcpy(&(neigh_info.ip_addr), &gateway,
                       sizeof(switchlink_ip_addr_t));
                neigh_info.intf_h = ifinfo.intf_h;
                neigh_info.vrf_h = vrf_h;
                status = switchlink_db_neighbor_get_info(&neigh_info);
                if (status == SWITCHLINK_DB_STATUS_SUCCESS) {
                    ecmp_info.nhops[ecmp_info.num_nhops] = neigh_info.nhop_h;
                } else {
                    ecmp_info.nhops[ecmp_info.num_nhops] = g_cpu_rx_nhop_h;
                }
                ecmp_info.num_nhops++;
                assert(ecmp_info.num_nhops < SWITCHLINK_ECMP_NUM_MEMBERS_MAX);
            }
        }
        rnh = RTNH_NEXT(rnh);
    }

    if (!ecmp_info.num_nhops) {
        return 0;
    }

    status = switchlink_db_ecmp_get_info(&ecmp_info);
    if (status == SWITCHLINK_DB_STATUS_ITEM_NOT_FOUND) {
        switchlink_ecmp_create(&ecmp_info);
        switchlink_db_ecmp_add(&ecmp_info);
    }

    return ecmp_info.ecmp_h;
}