summaryrefslogtreecommitdiffstats
path: root/src/plugins/lacp/rx_machine.c
AgeCommit message (Collapse)AuthorFilesLines
2018-03-30lacp: faster convergence for slow-rate config optionSteven1-3/+3
Do fast-rate if we are not yet synchronized with the partner. Stop sending LACP updates as a flash in the worker thread. Just expire the timer and let the lacp_process handle sending LACP PDU. Change-Id: I8b36fe74e752e7f45bd4a8d70512c0341cc197a1 Signed-off-by: Steven <sluong@cisco.com>
2018-03-21bond: Add bonding driver and LACP protocolSteven1-0/+425
Add bonding driver to support creation of bond interface which composes of multiple slave interfaces. The slave interfaces could be physical interfaces, or just any virtual interfaces. For example, memif interfaces. The syntax to create a bond interface is create bond mode <lacp | xor | acitve-backup | broadcast | round-robin> To enslave an interface to the bond interface, enslave interface TenGigabitEthernet6/0/0 to BondEthernet0 Please see src/plugins/lacp/lacp_doc.md for more examples and additional options. LACP is a control plane protocol which manages and monitors the status of the slave interfaces. The protocol is part of 802.3ad standard. This patch implements LACPv1. LACPv2 is not supported. To enable LACP on the bond interface, specify "mode lacp" when the bond interface is created. The syntax to enslave a slave interface is the same as other bonding modes. Change-Id: I06581d3b87635972f9f0e1ec50b67560fc13e26c Signed-off-by: Steven <sluong@cisco.com>
>125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 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
/*
 * Copyright (c) 2018 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 <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/vfio.h>
#include <sys/ioctl.h>

#include <vppinfra/linux/sysfs.h>

#include <vlib/vlib.h>
#include <vlib/unix/unix.h>
#include <vlib/pci/pci.h>
#include <vlib/linux/vfio.h>
#include <vlib/physmem.h>

#ifndef VFIO_NOIOMMU_IOMMU
#define VFIO_NOIOMMU_IOMMU 8
#endif

linux_vfio_main_t vfio_main;

clib_error_t *
vfio_map_physmem_page (vlib_main_t * vm, void *addr)
{
  vlib_physmem_main_t *vpm = &vm->physmem_main;
  linux_vfio_main_t *lvm = &vfio_main;
  struct vfio_iommu_type1_dma_map dm = { 0 };
  uword log2_page_size = vpm->pmalloc_main->def_log2_page_sz;
  uword physmem_start = pointer_to_uword (vpm->pmalloc_main->base);

  if (lvm->container_fd == -1)
    return clib_error_return (0, "No cointainer fd");

  u32 page_index = vlib_physmem_get_page_index (vm, addr);

  if (clib_bitmap_get (lvm->physmem_pages_mapped, page_index))
    {
      vlib_log_debug (lvm->log_default, "map DMA va:%p page:%u already "
		      "mapped", addr, page_index);
      return 0;
    }

  dm.argsz = sizeof (struct vfio_iommu_type1_dma_map);
  dm.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE;
  dm.vaddr = physmem_start + (page_index << log2_page_size);
  dm.size = 1ULL << log2_page_size;
  dm.iova = dm.vaddr;
  vlib_log_debug (lvm->log_default, "map DMA page:%u va:0x%lx iova:%lx "
		  "size:0x%lx", page_index, dm.vaddr, dm.iova, dm.size);

  if (ioctl (lvm->container_fd, VFIO_IOMMU_MAP_DMA, &dm) == -1)
    {
      vlib_log_err (lvm->log_default, "map DMA page:%u va:0x%lx iova:%lx "
		    "size:0x%lx failed, error %s (errno %d)", page_index,
		    dm.vaddr, dm.iova, dm.size, strerror (errno), errno);
      return clib_error_return_unix (0, "physmem DMA map failed");
    }

  lvm->physmem_pages_mapped = clib_bitmap_set (lvm->physmem_pages_mapped,
					       page_index, 1);
  return 0;
}

static linux_pci_vfio_iommu_group_t *
get_vfio_iommu_group (int group)
{
  linux_vfio_main_t *lvm = &vfio_main;
  uword *p;

  p = hash_get (lvm->iommu_pool_index_by_group, group);

  return p ? pool_elt_at_index (lvm->iommu_groups, p[0]) : 0;
}

static clib_error_t *
open_vfio_iommu_group (int group, int is_noiommu)
{
  linux_vfio_main_t *lvm = &vfio_main;
  linux_pci_vfio_iommu_group_t *g;
  clib_error_t *err = 0;
  struct vfio_group_status group_status;
  u8 *s = 0;
  int fd;

  if (lvm->container_fd == -1)
    {
      if ((fd = open ("/dev/vfio/vfio", O_RDWR)) == -1)
	return clib_error_return_unix (0, "failed to open VFIO container");

      if (ioctl (fd, VFIO_GET_API_VERSION) != VFIO_API_VERSION)
	{
	  close (fd);
	  return clib_error_return_unix (0, "incompatible VFIO version");
	}

      lvm->iommu_pool_index_by_group = hash_create (0, sizeof (uword));
      lvm->container_fd = fd;
    }

  g = get_vfio_iommu_group (group);
  if (g)
    {
      g->refcnt++;
      return 0;
    }
  s = format (s, "/dev/vfio/%s%u%c", is_noiommu ? "noiommu-" : "", group, 0);
  fd = open ((char *) s, O_RDWR);
  if (fd < 0)
    return clib_error_return_unix (0, "open '%s'", s);

  group_status.argsz = sizeof (group_status);
  if (ioctl (fd, VFIO_GROUP_GET_STATUS, &group_status) < 0)
    {
      err = clib_error_return_unix (0, "ioctl(VFIO_GROUP_GET_STATUS) '%s'",
				    s);
      goto error;
    }

  if (!(group_status.flags & VFIO_GROUP_FLAGS_VIABLE))
    {
      err = clib_error_return (0, "iommu group %d is not viable (not all "
			       "devices in this group bound to vfio-pci)",
			       group);
      goto error;
    }

  if (ioctl (fd, VFIO_GROUP_SET_CONTAINER, &lvm->container_fd) < 0)
    {
      err = clib_error_return_unix (0, "ioctl(VFIO_GROUP_SET_CONTAINER) '%s'",
				    s);
      goto error;
    }

  if (lvm->iommu_mode == 0)
    {
      if (is_noiommu)
	lvm->iommu_mode = VFIO_NOIOMMU_IOMMU;
      else
	lvm->iommu_mode = VFIO_TYPE1_IOMMU;

      if (ioctl (lvm->container_fd, VFIO_SET_IOMMU, lvm->iommu_mode) < 0)
	{
	  err = clib_error_return_unix (0, "ioctl(VFIO_SET_IOMMU) "
					"'/dev/vfio/vfio'");
	  goto error;
	}
    }


  pool_get (lvm->iommu_groups, g);
  g->fd = fd;
  g->refcnt = 1;
  hash_set (lvm->iommu_pool_index_by_group, group, g - lvm->iommu_groups);
  vec_free (s);
  return 0;
error:
  close (fd);
  return err;
}

clib_error_t *
linux_vfio_group_get_device_fd (vlib_pci_addr_t * addr, int *fdp,
				int *is_noiommu)
{
  clib_error_t *err = 0;
  linux_pci_vfio_iommu_group_t *g;
  u8 *s = 0;
  int iommu_group;
  u8 *tmpstr;
  int fd;

  *is_noiommu = 0;
  s = format (s, "/sys/bus/pci/devices/%U/iommu_group", format_vlib_pci_addr,
	      addr);
  tmpstr = clib_sysfs_link_to_name ((char *) s);
  if (tmpstr)
    {
      iommu_group = atoi ((char *) tmpstr);
      vec_free (tmpstr);
    }
  else
    {
      err = clib_error_return (0, "Cannot find IOMMU group for PCI device ",
			       "'%U'", format_vlib_pci_addr, addr);
      goto error;
    }
  vec_reset_length (s);

  s = format (s, "/sys/bus/pci/devices/%U/iommu_group/name",
	      format_vlib_pci_addr, addr);
  err = clib_sysfs_read ((char *) s, "%s", &tmpstr);
  if (err == 0)
    {
      if (strncmp ((char *) tmpstr, "vfio-noiommu", 12) == 0)
	*is_noiommu = 1;

      vec_free (tmpstr);
    }
  else
    clib_error_free (err);
  vec_reset_length (s);
  if ((err = open_vfio_iommu_group (iommu_group, *is_noiommu)))
    return err;

  g = get_vfio_iommu_group (iommu_group);

  s = format (s, "%U%c", format_vlib_pci_addr, addr, 0);
  if ((fd = ioctl (g->fd, VFIO_GROUP_GET_DEVICE_FD, (char *) s)) < 0)
    {
      err = clib_error_return_unix (0, "ioctl(VFIO_GROUP_GET_DEVICE_FD) '%U'",
				    format_vlib_pci_addr, addr);
      goto error;
    }
  vec_reset_length (s);

  *fdp = fd;

error:
  vec_free (s);
  return err;
}

clib_error_t *
linux_vfio_init (vlib_main_t * vm)
{
  linux_vfio_main_t *lvm = &vfio_main;

  lvm->log_default = vlib_log_register_class ("vfio", 0);
  lvm->container_fd = -1;

  return 0;
}

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