aboutsummaryrefslogtreecommitdiffstats
path: root/test/vpp_lo_interface.py
AgeCommit message (Collapse)AuthorFilesLines
2017-01-09make test: Loopback interface CRUD testMatej Klotton1-4/+26
Change-Id: I0581da7a682bfe4dd6520ecf1b2ea6bd8c20b1b3 Signed-off-by: Matej Klotton <mklotton@cisco.com>
2016-11-24Remove postinit from make-test interfacesMatej Klotton1-4/+3
Change-Id: I1eb0f735c5d025e6096d5760eb01419a1c58530a Signed-off-by: Matej Klotton <mklotton@cisco.com>
2016-11-15Update test documentation.Matej Klotton1-3/+1
- update IRB, IPv4, ipv6 doc - revert 778c2765c8ea5c6628f6d668847f0b9ae06dbf3d Change-Id: I9af5ed9329ce5fe01392cf28d5bf321cfc647e48 Signed-off-by: Matej Klotton <mklotton@cisco.com>
2016-11-11Add IRB testMatej Klotton1-0/+16
- JIRA: CSIT-255 - create loopback interfaces - move pg-interface specific arp and neighbor discovery from vpp_interface to vpp_pg_interface - base configuration of IRB tests - IP test scenario Change-Id: I9945a188163652a4e22325877aef008c4d029557 Signed-off-by: Matej Klotton <mklotton@cisco.com>
'>164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
/*
 * Copyright (c) 2020 Cisco and/or its affiliates.
 * 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.
 */

#include <arpa/inet.h>
#include <hicn/http-proxy/forwarder_interface.h>
#include <hicn/transport/utils/log.h>

#include <chrono>
#include <iostream>
#include <thread>
#include <unordered_set>

namespace transport {

ForwarderInterface::~ForwarderInterface() {}

int ForwarderInterface::connectToForwarder() {
  sock_ = hc_sock_create();
  if (!sock_) return -1;

  if (hc_sock_connect(sock_) < 0) {
    hc_sock_free(sock_);
    sock_ = nullptr;
    return -1;
  }

  return 0;
}

void ForwarderInterface::close() {
  if (!closed_) {
    internal_ioservice_.post([this]() {
      work_.reset();
      if (sock_) {
        hc_sock_free(sock_);
        sock_ = nullptr;
      }
    });

    if (thread_->joinable()) {
      thread_->join();
    }
  }
}

void ForwarderInterface::removeConnectedUserNow(uint32_t route_id) {
  internalRemoveConnectedUser(route_id);
}

void ForwarderInterface::scheduleRemoveConnectedUser(uint32_t route_id) {
  internal_ioservice_.post(
      [this, route_id]() { internalRemoveConnectedUser(route_id); });
}

int32_t ForwarderInterface::getMainListenerPort() {
  if (!sock_) return -1;

  hc_data_t *data;
  if (hc_listener_list(sock_, &data) < 0) return -1;

  int ret = -1;
  foreach_listener(l, data) {
    std::string interface = std::string(l->interface_name);
    if (interface.compare("lo") != 0) {
      ret = l->local_port;
      break;
    }
  }

  hc_data_free(data);
  return ret;
}

void ForwarderInterface::internalRemoveConnectedUser(uint32_t route_id) {
  auto it = route_status_.find(route_id);
  if (it == route_status_.end()) return;

  if (!sock_) return;

  // remove route
  hc_data_t *data;
  if (hc_route_list(sock_, &data) < 0) return;

  std::vector<hc_route_t *> routes_to_remove;
  foreach_route(r, data) {
    char remote_addr[INET6_ADDRSTRLEN];
    int ret = ip_address_ntop(&r->remote_addr, remote_addr, r->len, r->family);
    if (ret < 0) continue;

    std::string route_addr(remote_addr);
    if (route_addr.compare(it->second->route_addr) == 0 &&
        r->len == it->second->route_len) {
      // route found
      routes_to_remove.push_back(r);
    }
  }

  route_status_.erase(it);

  if (routes_to_remove.size() == 0) {
    // nothing to do here
    hc_data_free(data);
    return;
  }

  std::unordered_set<uint32_t> connids_to_remove;
  for (unsigned i = 0; i < routes_to_remove.size(); i++) {
    connids_to_remove.insert(routes_to_remove[i]->face_id);
    if (hc_route_delete(sock_, routes_to_remove[i]) < 0) {
      TRANSPORT_LOGE("Error removing route from forwarder.");
    }
  }

  // remove connection
  if (hc_connection_list(sock_, &data) < 0) {
    hc_data_free(data);
    return;
  }

  // collects pointerst to the connections using the conn IDs
  std::vector<hc_connection_t *> conns_to_remove;
  foreach_connection(c, data) {
    if (connids_to_remove.find(c->id) != connids_to_remove.end()) {
      // conn found
      conns_to_remove.push_back(c);
    }
  }

  if (conns_to_remove.size() == 0) {
    // nothing else to do here
    hc_data_free(data);
    return;
  }

  for (unsigned i = 0; i < conns_to_remove.size(); i++) {
    if (hc_connection_delete(sock_, conns_to_remove[i]) < 0) {
      TRANSPORT_LOGE("Error removing connection from forwarder.");
    }
  }

  hc_data_free(data);
}

void ForwarderInterface::internalCreateFaceAndRoute(RouteInfoPtr route_info,
                                                    uint8_t max_try,
                                                    asio::steady_timer *timer,
                                                    SetRouteCallback callback) {
  int ret = tryToCreateFaceAndRoute(route_info.get());

  if (ret < 0 && max_try > 0) {
    max_try--;
    timer->expires_from_now(std::chrono::milliseconds(500));
    timer->async_wait([this, _route_info = std::move(route_info), max_try,
                       timer, callback](std::error_code ec) {
      if (ec) return;
      internalCreateFaceAndRoute(std::move(_route_info), max_try, timer,
                                 std::move(callback));
    });
    return;
  }

  if (max_try == 0 && ret < 0) {
    pending_add_route_counter_--;
    external_ioservice_.post([callback]() { callback(false, ~0); });
  } else {
    pending_add_route_counter_--;
    route_status_[route_id_] = std::move(route_info);
    external_ioservice_.post(
        [route_id = route_id_, callback]() { callback(route_id, true); });
    route_id_++;
  }

  delete timer;
}

int ForwarderInterface::tryToCreateFaceAndRoute(route_info_t *route_info) {
  if (!sock_) return -1;

  hc_data_t *data;
  if (hc_listener_list(sock_, &data) < 0) {
    return -1;
  }

  bool found = false;
  uint32_t face_id;

  foreach_listener(l, data) {
    std::string interface = std::string(l->interface_name);
    if (interface.compare("lo") != 0) {
      found = true;

      ip_address_t remote_ip;
      if (ip_address_pton(route_info->remote_addr.c_str(), &remote_ip) < 0) {
        hc_data_free(data);
        return -1;
      }

      hc_face_t face;
      memset(&face, 0, sizeof(hc_face_t));

      face.face.type = FACE_TYPE_UDP;
      face.face.family = route_info->family;
      face.face.local_addr = l->local_addr;
      face.face.remote_addr = remote_ip;
      face.face.local_port = l->local_port;
      face.face.remote_port = route_info->remote_port;

      if (netdevice_set_name(&face.face.netdevice, l->interface_name) < 0) {
        hc_data_free(data);
        return -1;
      }

      if (hc_face_create(sock_, &face) < 0) {
        hc_data_free(data);
        return -1;
      }

      face_id = face.id;
      break;
    }
  }

  if (!found) {
    hc_data_free(data);
    return -1;
  }

  ip_address_t route_ip;
  hc_route_t route;

  if (ip_address_pton(route_info->route_addr.c_str(), &route_ip) < 0) {
    hc_data_free(data);
    return -1;
  }

  route.face_id = face_id;
  route.family = AF_INET6;
  route.remote_addr = route_ip;
  route.len = route_info->route_len;
  route.cost = 1;

  if (hc_route_create(sock_, &route) < 0) {
    hc_data_free(data);
    return -1;
  }

  hc_data_free(data);
  return 0;
}

}  // namespace transport