summaryrefslogtreecommitdiffstats
path: root/src/vnet/devices/virtio/virtio.h
diff options
context:
space:
mode:
authorMohsin Kazmi <sykazmi@cisco.com>2020-08-20 10:25:12 +0200
committerBenoƮt Ganne <bganne@cisco.com>2020-08-20 14:12:40 +0000
commit379aac395a2cc78847d8f14264a22a3ee99fc1c2 (patch)
treecbc2031fa11c7b37e298cd5f2aca28a0714183a2 /src/vnet/devices/virtio/virtio.h
parent7885c740ae5ea4dd97e11a5b1b33c394bc5b5664 (diff)
virtio: add modern device support
Type: feature Change-Id: I205f7c146a213d603d9d1e46fcf5195a876608dc Signed-off-by: Mohsin Kazmi <sykazmi@cisco.com>
Diffstat (limited to 'src/vnet/devices/virtio/virtio.h')
-rw-r--r--src/vnet/devices/virtio/virtio.h70
1 files changed, 46 insertions, 24 deletions
diff --git a/src/vnet/devices/virtio/virtio.h b/src/vnet/devices/virtio/virtio.h
index e1ba71dae2e..7a5dcd83fe3 100644
--- a/src/vnet/devices/virtio/virtio.h
+++ b/src/vnet/devices/virtio/virtio.h
@@ -57,7 +57,7 @@
/* The Host publishes the avail index for which it expects a kick \
* at the end of the used ring. Guest should ignore the used->flags field. */ \
_ (VHOST_USER_F_PROTOCOL_FEATURES, 30) \
- _ (VIRTIO_F_VERSION_1, 32)
+ _ (VIRTIO_F_VERSION_1, 32) /* v1.0 compliant. */ \
#define foreach_virtio_if_flag \
_(0, ADMIN_UP, "admin-up") \
@@ -130,6 +130,7 @@ typedef union
u32 as_u32;
} pci_addr_t;
+/* forward declaration */
typedef struct _virtio_pci_func virtio_pci_func_t;
typedef struct
@@ -161,35 +162,49 @@ typedef struct
CLIB_CACHE_LINE_ALIGN_MARK (cacheline1);
int packet_coalesce;
- union
- {
- u32 id;
- pci_addr_t pci_addr;
- };
- int *vhost_fds;
u32 dev_instance;
u32 numa_node;
u64 remote_features;
/* error */
clib_error_t *error;
- u8 support_int_mode; /* support interrupt mode */
- u16 max_queue_pairs;
- u16 msix_table_size;
- u8 status;
u8 mac_addr[6];
- u8 *host_if_name;
- u8 *net_ns;
- u8 *host_bridge;
- u8 host_mac_addr[6];
- ip4_address_t host_ip4_addr;
- u8 host_ip4_prefix_len;
- ip6_address_t host_ip6_addr;
- u8 host_ip6_prefix_len;
- u32 host_mtu_size;
- u32 tap_flags;
- int ifindex;
- virtio_vring_t *cxq_vring;
+ union
+ {
+ struct /* tun/tap interface */
+ {
+ ip6_address_t host_ip6_addr;
+ int *vhost_fds;
+ u8 *host_if_name;
+ u8 *net_ns;
+ u8 *host_bridge;
+ u8 host_mac_addr[6];
+ u32 id;
+ u32 host_mtu_size;
+ u32 tap_flags;
+ int ifindex;
+ ip4_address_t host_ip4_addr;
+ u8 host_ip4_prefix_len;
+ u8 host_ip6_prefix_len;
+ };
+ struct /* native virtio */
+ {
+ void *bar;
+ virtio_vring_t *cxq_vring;
+ pci_addr_t pci_addr;
+ u32 bar_id;
+ u32 notify_off_multiplier;
+ u32 is_modern;
+ u16 common_offset;
+ u16 notify_offset;
+ u16 device_offset;
+ u16 isr_offset;
+ u16 max_queue_pairs;
+ u16 msix_table_size;
+ u8 support_int_mode; /* support interrupt mode */
+ u8 status;
+ };
+ };
const virtio_pci_func_t *virtio_pci_func;
} virtio_if_t;
@@ -221,6 +236,8 @@ extern void virtio_show (vlib_main_t * vm, u32 * hw_if_indices, u8 show_descr,
extern void virtio_set_packet_coalesce (virtio_if_t * vif);
extern void virtio_pci_legacy_notify_queue (vlib_main_t * vm,
virtio_if_t * vif, u16 queue_id);
+extern void virtio_pci_modern_notify_queue (vlib_main_t * vm,
+ virtio_if_t * vif, u16 queue_id);
format_function_t format_virtio_device_name;
format_function_t format_virtio_log_name;
@@ -228,7 +245,12 @@ static_always_inline void
virtio_kick (vlib_main_t * vm, virtio_vring_t * vring, virtio_if_t * vif)
{
if (vif->type == VIRTIO_IF_TYPE_PCI)
- virtio_pci_legacy_notify_queue (vm, vif, vring->queue_id);
+ {
+ if (vif->is_modern)
+ virtio_pci_modern_notify_queue (vm, vif, vring->queue_id);
+ else
+ virtio_pci_legacy_notify_queue (vm, vif, vring->queue_id);
+ }
else
{
u64 x = 1;
f='#n337'>337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
/*
 * Copyright (c) 2017 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 <boost/algorithm/string.hpp>
#include <sstream>

#include "vom/prefix.hpp"

namespace VOM {
/*
 * Keep this in sync with VPP's fib_protocol_t
 */
const l3_proto_t l3_proto_t::IPV4(0, "ipv4");
const l3_proto_t l3_proto_t::IPV6(1, "ipv6");
const l3_proto_t l3_proto_t::MPLS(2, "mpls");

l3_proto_t::l3_proto_t(int v, const std::string& s)
  : enum_base<l3_proto_t>(v, s)
{
}

bool
l3_proto_t::is_ipv6()
{
  return (*this == IPV6);
}

bool
l3_proto_t::is_ipv4()
{
  return (*this == IPV4);
}

const l3_proto_t&
l3_proto_t::from_address(const boost::asio::ip::address& addr)
{
  if (addr.is_v6()) {
    return IPV6;
  }

  return IPV4;
}

const nh_proto_t&
l3_proto_t::to_nh_proto() const
{
  if (*this == IPV4)
    return nh_proto_t::IPV4;
  else if (*this == IPV6)
    return nh_proto_t::IPV6;
  else if (*this == MPLS)
    return nh_proto_t::MPLS;

  return nh_proto_t::IPV4;
}

std::ostream&
operator<<(std::ostream& os, const l3_proto_t& l3p)
{
  os << l3p.to_string();
  return os;
}

/*
 * Keep this in sync with VPP's dpo_proto_t
 */
const nh_proto_t nh_proto_t::IPV4(0, "ipv4");
const nh_proto_t nh_proto_t::IPV6(1, "ipv6");
const nh_proto_t nh_proto_t::MPLS(2, "mpls");
const nh_proto_t nh_proto_t::ETHERNET(3, "ethernet");

nh_proto_t::nh_proto_t(int v, const std::string& s)
  : enum_base<nh_proto_t>(v, s)
{
}

const nh_proto_t&
nh_proto_t::from_address(const boost::asio::ip::address& addr)
{
  if (addr.is_v6()) {
    return IPV6;
  }

  return IPV4;
}

/**
 * The all Zeros prefix
 */
const route::prefix_t route::prefix_t::ZERO("0.0.0.0", 0);
const route::prefix_t route::prefix_t::ZEROv6("::", 0);

route::prefix_t::prefix_t(const boost::asio::ip::address& addr, uint8_t len)
  : m_addr(addr)
  , m_len(len)
{
}

route::prefix_t::prefix_t(const boost::asio::ip::address& addr)
  : m_addr(addr)
  , m_len(VOM::mask_width(addr))
{
}

route::prefix_t::prefix_t(const std::string& s, uint8_t len)
  : m_addr(boost::asio::ip::address::from_string(s))
  , m_len(len)
{
}

route::prefix_t::prefix_t(const prefix_t& o)
  : m_addr(o.m_addr)
  , m_len(o.m_len)
{
}

route::prefix_t::prefix_t()
  : m_addr()
  , m_len(0)
{
}

route::prefix_t::~prefix_t()
{
}

route::prefix_t&
route::prefix_t::operator=(const route::prefix_t& o)
{
  m_addr = o.m_addr;
  m_len = o.m_len;

  return (*this);
}

const boost::asio::ip::address&
route::prefix_t::address() const
{
  return (m_addr);
}

uint8_t
route::prefix_t::mask_width() const
{
  return (m_len);
}

bool
route::prefix_t::operator<(const route::prefix_t& o) const
{
  if (m_len == o.m_len) {
    return (m_addr < o.m_addr);
  } else {
    return (m_len < o.m_len);
  }
}

bool
route::prefix_t::operator==(const route::prefix_t& o) const
{
  return (m_len == o.m_len && m_addr == o.m_addr);
}

bool
route::prefix_t::operator!=(const route::prefix_t& o) const
{
  return (!(*this == o));
}

std::string
route::prefix_t::to_string() const
{
  std::ostringstream s;

  s << m_addr.to_string() << "/" << std::to_string(m_len);

  return (s.str());
}

boost::asio::ip::address
from_bytes(uint8_t is_ip6, uint8_t* bytes)
{
  boost::asio::ip::address addr;

  if (is_ip6) {
    std::array<uint8_t, 16> a;
    std::copy(bytes, bytes + 16, std::begin(a));
    boost::asio::ip::address_v6 v6(a);
    addr = v6;
  } else {
    std::array<uint8_t, 4> a;
    std::copy(bytes, bytes + 4, std::begin(a));
    boost::asio::ip::address_v4 v4(a);
    addr = v4;
  }

  return (addr);
}

route::prefix_t::prefix_t(uint8_t is_ip6, uint8_t* addr, uint8_t len)
  : m_addr(from_bytes(is_ip6, addr))
  , m_len(len)
{
}
void
to_bytes(const boost::asio::ip::address_v6& addr, uint8_t* array)
{
  memcpy(array, addr.to_bytes().data(), 16);
}

void
to_bytes(const boost::asio::ip::address_v4& addr, uint8_t* array)
{
  memcpy(array, addr.to_bytes().data(), 4);
}

void
to_bytes(const boost::asio::ip::address& addr, uint8_t* is_ip6, uint8_t* array)
{
  if (addr.is_v6()) {
    *is_ip6 = 1;
    to_bytes(addr.to_v6(), array);
  } else {
    *is_ip6 = 0;
    to_bytes(addr.to_v4(), array);
  }
}

uint32_t
mask_width(const boost::asio::ip::address& addr)
{
  if (addr.is_v6()) {
    return 128;
  }
  return 32;
}

void
route::prefix_t::to_vpp(uint8_t* is_ip6, uint8_t* addr, uint8_t* len) const
{
  *len = m_len;
  to_bytes(m_addr, is_ip6, addr);
}

l3_proto_t
route::prefix_t::l3_proto() const
{
  if (m_addr.is_v6()) {
    return (l3_proto_t::IPV6);
  } else {
    return (l3_proto_t::IPV4);
  }

  return (l3_proto_t::IPV4);
}

std::ostream&
operator<<(std::ostream& os, const route::prefix_t& pfx)
{
  os << pfx.to_string();

  return (os);
}

boost::asio::ip::address_v4
operator|(const boost::asio::ip::address_v4& addr1,
          const boost::asio::ip::address_v4& addr2)
{
  uint32_t a;
  a = addr1.to_ulong() | addr2.to_ulong();
  boost::asio::ip::address_v4 addr(a);
  return (addr);
}

boost::asio::ip::address_v4 operator&(const boost::asio::ip::address_v4& addr1,
                                      const boost::asio::ip::address_v4& addr2)
{
  uint32_t a;
  a = addr1.to_ulong() & addr2.to_ulong();
  boost::asio::ip::address_v4 addr(a);
  return (addr);
}

boost::asio::ip::address_v4 operator~(const boost::asio::ip::address_v4& addr1)
{
  uint32_t a;
  a = ~addr1.to_ulong();
  boost::asio::ip::address_v4 addr(a);
  return (addr);
}

boost::asio::ip::address_v6
operator|(const boost::asio::ip::address_v6& addr1,
          const boost::asio::ip::address_v6& addr2)
{
  boost::asio::ip::address_v6::bytes_type b1 = addr1.to_bytes();
  boost::asio::ip::address_v6::bytes_type b2 = addr2.to_bytes();

  for (boost::asio::ip::address_v6::bytes_type::size_type ii = 0;
       ii < b1.max_size(); ii++) {
    b1[ii] |= b2[ii];
  }

  boost::asio::ip::address_v6 addr(b1);
  return (addr);
}

boost::asio::ip::address_v6 operator&(const boost::asio::ip::address_v6& addr1,
                                      const boost::asio::ip::address_v6& addr2)
{
  boost::asio::ip::address_v6::bytes_type b1 = addr1.to_bytes();
  boost::asio::ip::address_v6::bytes_type b2 = addr2.to_bytes();

  for (boost::asio::ip::address_v6::bytes_type::size_type ii = 0;
       ii < b1.max_size(); ii++) {
    b1[ii] &= b2[ii];
  }

  boost::asio::ip::address_v6 addr(b1);
  return (addr);
}

boost::asio::ip::address_v6 operator~(const boost::asio::ip::address_v6& addr1)
{
  boost::asio::ip::address_v6::bytes_type b1 = addr1.to_bytes();

  for (boost::asio::ip::address_v6::bytes_type::size_type ii = 0;
       ii < b1.max_size(); ii++) {
    b1[ii] = ~b1[ii];
  }

  boost::asio::ip::address_v6 addr(b1);
  return (addr);
}
boost::asio::ip::address
operator|(const boost::asio::ip::address& addr1,
          const boost::asio::ip::address& addr2)
{
  if (addr1.is_v6())
    return (addr1.to_v6() | addr2.to_v6());
  else
    return (addr1.to_v4() | addr2.to_v4());
}

boost::asio::ip::address operator&(const boost::asio::ip::address& addr1,
                                   const boost::asio::ip::address& addr2)
{
  if (addr1.is_v6())
    return (addr1.to_v6() & addr2.to_v6());
  else
    return (addr1.to_v4() & addr2.to_v4());
}

boost::asio::ip::address operator~(const boost::asio::ip::address& addr1)
{
  if (addr1.is_v6())
    return ~(addr1.to_v6());
  else
    return ~(addr1.to_v4());
}

boost::asio::ip::address
route::prefix_t::mask() const
{
  if (m_addr.is_v6()) {
    boost::asio::ip::address_v6::bytes_type b =
      boost::asio::ip::address_v6::any().to_bytes();

    uint8_t n_bits = mask_width();

    for (boost::asio::ip::address_v6::bytes_type::size_type ii = 0;
         ii < b.max_size(); ii++) {
      for (int8_t bit = 7; bit >= 0 && n_bits; bit--) {
        b[ii] |= (1 << bit);
        n_bits--;
      }
      if (!n_bits)
        break;
    }

    return (boost::asio::ip::address_v6(b));
  } else {
    uint32_t a;

    a = ~((1 << (32 - mask_width())) - 1);

    return (boost::asio::ip::address_v4(a));
  }
}

route::prefix_t
route::prefix_t::low() const
{
  prefix_t pfx(*this);

  pfx.m_addr = pfx.m_addr & pfx.mask();

  return (pfx);
}

route::prefix_t
route::prefix_t::high() const
{
  prefix_t pfx(*this);

  pfx.m_addr = pfx.m_addr | ~pfx.mask();

  return (pfx);
}

}; // namespace VOM

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "mozilla")
 * End:
 */