diff options
author | RajithaY <rajithax.yerrumsetty@intel.com> | 2017-04-25 03:31:15 -0700 |
---|---|---|
committer | Rajitha Yerrumchetty <rajithax.yerrumsetty@intel.com> | 2017-05-22 06:48:08 +0000 |
commit | bb756eebdac6fd24e8919e2c43f7d2c8c4091f59 (patch) | |
tree | ca11e03542edf2d8f631efeca5e1626d211107e3 /qemu/hw/net/rocker | |
parent | a14b48d18a9ed03ec191cf16b162206998a895ce (diff) |
Adding qemu as a submodule of KVMFORNFV
This Patch includes the changes to add qemu as a submodule to
kvmfornfv repo and make use of the updated latest qemu for the
execution of all testcase
Change-Id: I1280af507a857675c7f81d30c95255635667bdd7
Signed-off-by:RajithaY<rajithax.yerrumsetty@intel.com>
Diffstat (limited to 'qemu/hw/net/rocker')
-rw-r--r-- | qemu/hw/net/rocker/qmp-norocker.c | 51 | ||||
-rw-r--r-- | qemu/hw/net/rocker/rocker.c | 1584 | ||||
-rw-r--r-- | qemu/hw/net/rocker/rocker.h | 84 | ||||
-rw-r--r-- | qemu/hw/net/rocker/rocker_desc.c | 374 | ||||
-rw-r--r-- | qemu/hw/net/rocker/rocker_desc.h | 53 | ||||
-rw-r--r-- | qemu/hw/net/rocker/rocker_fp.c | 269 | ||||
-rw-r--r-- | qemu/hw/net/rocker/rocker_fp.h | 54 | ||||
-rw-r--r-- | qemu/hw/net/rocker/rocker_hw.h | 493 | ||||
-rw-r--r-- | qemu/hw/net/rocker/rocker_of_dpa.c | 2627 | ||||
-rw-r--r-- | qemu/hw/net/rocker/rocker_of_dpa.h | 22 | ||||
-rw-r--r-- | qemu/hw/net/rocker/rocker_tlv.h | 244 | ||||
-rw-r--r-- | qemu/hw/net/rocker/rocker_world.c | 102 | ||||
-rw-r--r-- | qemu/hw/net/rocker/rocker_world.h | 61 |
13 files changed, 0 insertions, 6018 deletions
diff --git a/qemu/hw/net/rocker/qmp-norocker.c b/qemu/hw/net/rocker/qmp-norocker.c deleted file mode 100644 index 6acbcdb02..000000000 --- a/qemu/hw/net/rocker/qmp-norocker.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * QMP Target options - Commands handled based on a target config - * versus a host config - * - * Copyright (c) 2015 David Ahern <dsahern@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "qmp-commands.h" -#include "qapi/qmp/qerror.h" - -RockerSwitch *qmp_query_rocker(const char *name, Error **errp) -{ - error_setg(errp, QERR_FEATURE_DISABLED, "rocker"); - return NULL; -}; - -RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp) -{ - error_setg(errp, QERR_FEATURE_DISABLED, "rocker"); - return NULL; -}; - -RockerOfDpaFlowList *qmp_query_rocker_of_dpa_flows(const char *name, - bool has_tbl_id, - uint32_t tbl_id, - Error **errp) -{ - error_setg(errp, QERR_FEATURE_DISABLED, "rocker"); - return NULL; -}; - -RockerOfDpaGroupList *qmp_query_rocker_of_dpa_groups(const char *name, - bool has_type, - uint8_t type, - Error **errp) -{ - error_setg(errp, QERR_FEATURE_DISABLED, "rocker"); - return NULL; -}; diff --git a/qemu/hw/net/rocker/rocker.c b/qemu/hw/net/rocker/rocker.c deleted file mode 100644 index 30f2ce417..000000000 --- a/qemu/hw/net/rocker/rocker.c +++ /dev/null @@ -1,1584 +0,0 @@ -/* - * QEMU rocker switch emulation - PCI device - * - * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com> - * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/pci/pci.h" -#include "hw/pci/msix.h" -#include "net/net.h" -#include "net/eth.h" -#include "qemu/iov.h" -#include "qemu/bitops.h" -#include "qmp-commands.h" - -#include "rocker.h" -#include "rocker_hw.h" -#include "rocker_fp.h" -#include "rocker_desc.h" -#include "rocker_tlv.h" -#include "rocker_world.h" -#include "rocker_of_dpa.h" - -struct rocker { - /* private */ - PCIDevice parent_obj; - /* public */ - - MemoryRegion mmio; - MemoryRegion msix_bar; - - /* switch configuration */ - char *name; /* switch name */ - char *world_name; /* world name */ - uint32_t fp_ports; /* front-panel port count */ - NICPeers *fp_ports_peers; - MACAddr fp_start_macaddr; /* front-panel port 0 mac addr */ - uint64_t switch_id; /* switch id */ - - /* front-panel ports */ - FpPort *fp_port[ROCKER_FP_PORTS_MAX]; - - /* register backings */ - uint32_t test_reg; - uint64_t test_reg64; - dma_addr_t test_dma_addr; - uint32_t test_dma_size; - uint64_t lower32; /* lower 32-bit val in 2-part 64-bit access */ - - /* desc rings */ - DescRing **rings; - - /* switch worlds */ - World *worlds[ROCKER_WORLD_TYPE_MAX]; - World *world_dflt; - - QLIST_ENTRY(rocker) next; -}; - -#define ROCKER "rocker" - -#define to_rocker(obj) \ - OBJECT_CHECK(Rocker, (obj), ROCKER) - -static QLIST_HEAD(, rocker) rockers; - -Rocker *rocker_find(const char *name) -{ - Rocker *r; - - QLIST_FOREACH(r, &rockers, next) - if (strcmp(r->name, name) == 0) { - return r; - } - - return NULL; -} - -World *rocker_get_world(Rocker *r, enum rocker_world_type type) -{ - if (type < ROCKER_WORLD_TYPE_MAX) { - return r->worlds[type]; - } - return NULL; -} - -RockerSwitch *qmp_query_rocker(const char *name, Error **errp) -{ - RockerSwitch *rocker; - Rocker *r; - - r = rocker_find(name); - if (!r) { - error_setg(errp, "rocker %s not found", name); - return NULL; - } - - rocker = g_new0(RockerSwitch, 1); - rocker->name = g_strdup(r->name); - rocker->id = r->switch_id; - rocker->ports = r->fp_ports; - - return rocker; -} - -RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp) -{ - RockerPortList *list = NULL; - Rocker *r; - int i; - - r = rocker_find(name); - if (!r) { - error_setg(errp, "rocker %s not found", name); - return NULL; - } - - for (i = r->fp_ports - 1; i >= 0; i--) { - RockerPortList *info = g_malloc0(sizeof(*info)); - info->value = g_malloc0(sizeof(*info->value)); - struct fp_port *port = r->fp_port[i]; - - fp_port_get_info(port, info); - info->next = list; - list = info; - } - - return list; -} - -uint32_t rocker_fp_ports(Rocker *r) -{ - return r->fp_ports; -} - -static uint32_t rocker_get_pport_by_tx_ring(Rocker *r, - DescRing *ring) -{ - return (desc_ring_index(ring) - 2) / 2 + 1; -} - -static int tx_consume(Rocker *r, DescInfo *info) -{ - PCIDevice *dev = PCI_DEVICE(r); - char *buf = desc_get_buf(info, true); - RockerTlv *tlv_frag; - RockerTlv *tlvs[ROCKER_TLV_TX_MAX + 1]; - struct iovec iov[ROCKER_TX_FRAGS_MAX] = { { 0, }, }; - uint32_t pport; - uint32_t port; - uint16_t tx_offload = ROCKER_TX_OFFLOAD_NONE; - uint16_t tx_l3_csum_off = 0; - uint16_t tx_tso_mss = 0; - uint16_t tx_tso_hdr_len = 0; - int iovcnt = 0; - int err = ROCKER_OK; - int rem; - int i; - - if (!buf) { - return -ROCKER_ENXIO; - } - - rocker_tlv_parse(tlvs, ROCKER_TLV_TX_MAX, buf, desc_tlv_size(info)); - - if (!tlvs[ROCKER_TLV_TX_FRAGS]) { - return -ROCKER_EINVAL; - } - - pport = rocker_get_pport_by_tx_ring(r, desc_get_ring(info)); - if (!fp_port_from_pport(pport, &port)) { - return -ROCKER_EINVAL; - } - - if (tlvs[ROCKER_TLV_TX_OFFLOAD]) { - tx_offload = rocker_tlv_get_u8(tlvs[ROCKER_TLV_TX_OFFLOAD]); - } - - switch (tx_offload) { - case ROCKER_TX_OFFLOAD_L3_CSUM: - if (!tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]) { - return -ROCKER_EINVAL; - } - break; - case ROCKER_TX_OFFLOAD_TSO: - if (!tlvs[ROCKER_TLV_TX_TSO_MSS] || - !tlvs[ROCKER_TLV_TX_TSO_HDR_LEN]) { - return -ROCKER_EINVAL; - } - break; - } - - if (tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]) { - tx_l3_csum_off = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]); - } - - if (tlvs[ROCKER_TLV_TX_TSO_MSS]) { - tx_tso_mss = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_TSO_MSS]); - } - - if (tlvs[ROCKER_TLV_TX_TSO_HDR_LEN]) { - tx_tso_hdr_len = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_TSO_HDR_LEN]); - } - - rocker_tlv_for_each_nested(tlv_frag, tlvs[ROCKER_TLV_TX_FRAGS], rem) { - hwaddr frag_addr; - uint16_t frag_len; - - if (rocker_tlv_type(tlv_frag) != ROCKER_TLV_TX_FRAG) { - err = -ROCKER_EINVAL; - goto err_bad_attr; - } - - rocker_tlv_parse_nested(tlvs, ROCKER_TLV_TX_FRAG_ATTR_MAX, tlv_frag); - - if (!tlvs[ROCKER_TLV_TX_FRAG_ATTR_ADDR] || - !tlvs[ROCKER_TLV_TX_FRAG_ATTR_LEN]) { - err = -ROCKER_EINVAL; - goto err_bad_attr; - } - - frag_addr = rocker_tlv_get_le64(tlvs[ROCKER_TLV_TX_FRAG_ATTR_ADDR]); - frag_len = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_FRAG_ATTR_LEN]); - - if (iovcnt >= ROCKER_TX_FRAGS_MAX) { - goto err_too_many_frags; - } - iov[iovcnt].iov_len = frag_len; - iov[iovcnt].iov_base = g_malloc(frag_len); - if (!iov[iovcnt].iov_base) { - err = -ROCKER_ENOMEM; - goto err_no_mem; - } - - if (pci_dma_read(dev, frag_addr, iov[iovcnt].iov_base, - iov[iovcnt].iov_len)) { - err = -ROCKER_ENXIO; - goto err_bad_io; - } - iovcnt++; - } - - if (iovcnt) { - /* XXX perform Tx offloads */ - /* XXX silence compiler for now */ - tx_l3_csum_off += tx_tso_mss = tx_tso_hdr_len = 0; - } - - err = fp_port_eg(r->fp_port[port], iov, iovcnt); - -err_too_many_frags: -err_bad_io: -err_no_mem: -err_bad_attr: - for (i = 0; i < ROCKER_TX_FRAGS_MAX; i++) { - g_free(iov[i].iov_base); - } - - return err; -} - -static int cmd_get_port_settings(Rocker *r, - DescInfo *info, char *buf, - RockerTlv *cmd_info_tlv) -{ - RockerTlv *tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1]; - RockerTlv *nest; - FpPort *fp_port; - uint32_t pport; - uint32_t port; - uint32_t speed; - uint8_t duplex; - uint8_t autoneg; - uint8_t learning; - char *phys_name; - MACAddr macaddr; - enum rocker_world_type mode; - size_t tlv_size; - int pos; - int err; - - rocker_tlv_parse_nested(tlvs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX, - cmd_info_tlv); - - if (!tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]) { - return -ROCKER_EINVAL; - } - - pport = rocker_tlv_get_le32(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]); - if (!fp_port_from_pport(pport, &port)) { - return -ROCKER_EINVAL; - } - fp_port = r->fp_port[port]; - - err = fp_port_get_settings(fp_port, &speed, &duplex, &autoneg); - if (err) { - return err; - } - - fp_port_get_macaddr(fp_port, &macaddr); - mode = world_type(fp_port_get_world(fp_port)); - learning = fp_port_get_learning(fp_port); - phys_name = fp_port_get_name(fp_port); - - tlv_size = rocker_tlv_total_size(0) + /* nest */ - rocker_tlv_total_size(sizeof(uint32_t)) + /* pport */ - rocker_tlv_total_size(sizeof(uint32_t)) + /* speed */ - rocker_tlv_total_size(sizeof(uint8_t)) + /* duplex */ - rocker_tlv_total_size(sizeof(uint8_t)) + /* autoneg */ - rocker_tlv_total_size(sizeof(macaddr.a)) + /* macaddr */ - rocker_tlv_total_size(sizeof(uint8_t)) + /* mode */ - rocker_tlv_total_size(sizeof(uint8_t)) + /* learning */ - rocker_tlv_total_size(strlen(phys_name)); - - if (tlv_size > desc_buf_size(info)) { - return -ROCKER_EMSGSIZE; - } - - pos = 0; - nest = rocker_tlv_nest_start(buf, &pos, ROCKER_TLV_CMD_INFO); - rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT, pport); - rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_SPEED, speed); - rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX, duplex); - rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG, autoneg); - rocker_tlv_put(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR, - sizeof(macaddr.a), macaddr.a); - rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_MODE, mode); - rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING, - learning); - rocker_tlv_put(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME, - strlen(phys_name), phys_name); - rocker_tlv_nest_end(buf, &pos, nest); - - return desc_set_buf(info, tlv_size); -} - -static int cmd_set_port_settings(Rocker *r, - RockerTlv *cmd_info_tlv) -{ - RockerTlv *tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1]; - FpPort *fp_port; - uint32_t pport; - uint32_t port; - uint32_t speed; - uint8_t duplex; - uint8_t autoneg; - uint8_t learning; - MACAddr macaddr; - enum rocker_world_type mode; - int err; - - rocker_tlv_parse_nested(tlvs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX, - cmd_info_tlv); - - if (!tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]) { - return -ROCKER_EINVAL; - } - - pport = rocker_tlv_get_le32(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]); - if (!fp_port_from_pport(pport, &port)) { - return -ROCKER_EINVAL; - } - fp_port = r->fp_port[port]; - - if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_SPEED] && - tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX] && - tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG]) { - - speed = rocker_tlv_get_le32(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_SPEED]); - duplex = rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX]); - autoneg = rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG]); - - err = fp_port_set_settings(fp_port, speed, duplex, autoneg); - if (err) { - return err; - } - } - - if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR]) { - if (rocker_tlv_len(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR]) != - sizeof(macaddr.a)) { - return -ROCKER_EINVAL; - } - memcpy(macaddr.a, - rocker_tlv_data(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR]), - sizeof(macaddr.a)); - fp_port_set_macaddr(fp_port, &macaddr); - } - - if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MODE]) { - mode = rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MODE]); - if (mode >= ROCKER_WORLD_TYPE_MAX) { - return -ROCKER_EINVAL; - } - /* We don't support world change. */ - if (!fp_port_check_world(fp_port, r->worlds[mode])) { - return -ROCKER_EINVAL; - } - } - - if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING]) { - learning = - rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING]); - fp_port_set_learning(fp_port, learning); - } - - return ROCKER_OK; -} - -static int cmd_consume(Rocker *r, DescInfo *info) -{ - char *buf = desc_get_buf(info, false); - RockerTlv *tlvs[ROCKER_TLV_CMD_MAX + 1]; - RockerTlv *info_tlv; - World *world; - uint16_t cmd; - int err; - - if (!buf) { - return -ROCKER_ENXIO; - } - - rocker_tlv_parse(tlvs, ROCKER_TLV_CMD_MAX, buf, desc_tlv_size(info)); - - if (!tlvs[ROCKER_TLV_CMD_TYPE] || !tlvs[ROCKER_TLV_CMD_INFO]) { - return -ROCKER_EINVAL; - } - - cmd = rocker_tlv_get_le16(tlvs[ROCKER_TLV_CMD_TYPE]); - info_tlv = tlvs[ROCKER_TLV_CMD_INFO]; - - /* This might be reworked to something like this: - * Every world will have an array of command handlers from - * ROCKER_TLV_CMD_TYPE_UNSPEC to ROCKER_TLV_CMD_TYPE_MAX. There is - * up to each world to implement whatever command it want. - * It can reference "generic" commands as cmd_set_port_settings or - * cmd_get_port_settings - */ - - switch (cmd) { - case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD: - case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD: - case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL: - case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_GET_STATS: - case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD: - case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD: - case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL: - case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS: - world = r->worlds[ROCKER_WORLD_TYPE_OF_DPA]; - err = world_do_cmd(world, info, buf, cmd, info_tlv); - break; - case ROCKER_TLV_CMD_TYPE_GET_PORT_SETTINGS: - err = cmd_get_port_settings(r, info, buf, info_tlv); - break; - case ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS: - err = cmd_set_port_settings(r, info_tlv); - break; - default: - err = -ROCKER_EINVAL; - break; - } - - return err; -} - -static void rocker_msix_irq(Rocker *r, unsigned vector) -{ - PCIDevice *dev = PCI_DEVICE(r); - - DPRINTF("MSI-X notify request for vector %d\n", vector); - if (vector >= ROCKER_MSIX_VEC_COUNT(r->fp_ports)) { - DPRINTF("incorrect vector %d\n", vector); - return; - } - msix_notify(dev, vector); -} - -int rocker_event_link_changed(Rocker *r, uint32_t pport, bool link_up) -{ - DescRing *ring = r->rings[ROCKER_RING_EVENT]; - DescInfo *info = desc_ring_fetch_desc(ring); - RockerTlv *nest; - char *buf; - size_t tlv_size; - int pos; - int err; - - if (!info) { - return -ROCKER_ENOBUFS; - } - - tlv_size = rocker_tlv_total_size(sizeof(uint16_t)) + /* event type */ - rocker_tlv_total_size(0) + /* nest */ - rocker_tlv_total_size(sizeof(uint32_t)) + /* pport */ - rocker_tlv_total_size(sizeof(uint8_t)); /* link up */ - - if (tlv_size > desc_buf_size(info)) { - err = -ROCKER_EMSGSIZE; - goto err_too_big; - } - - buf = desc_get_buf(info, false); - if (!buf) { - err = -ROCKER_ENOMEM; - goto err_no_mem; - } - - pos = 0; - rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_TYPE, - ROCKER_TLV_EVENT_TYPE_LINK_CHANGED); - nest = rocker_tlv_nest_start(buf, &pos, ROCKER_TLV_EVENT_INFO); - rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_LINK_CHANGED_PPORT, pport); - rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_EVENT_LINK_CHANGED_LINKUP, - link_up ? 1 : 0); - rocker_tlv_nest_end(buf, &pos, nest); - - err = desc_set_buf(info, tlv_size); - -err_too_big: -err_no_mem: - if (desc_ring_post_desc(ring, err)) { - rocker_msix_irq(r, ROCKER_MSIX_VEC_EVENT); - } - - return err; -} - -int rocker_event_mac_vlan_seen(Rocker *r, uint32_t pport, uint8_t *addr, - uint16_t vlan_id) -{ - DescRing *ring = r->rings[ROCKER_RING_EVENT]; - DescInfo *info; - FpPort *fp_port; - uint32_t port; - RockerTlv *nest; - char *buf; - size_t tlv_size; - int pos; - int err; - - if (!fp_port_from_pport(pport, &port)) { - return -ROCKER_EINVAL; - } - fp_port = r->fp_port[port]; - if (!fp_port_get_learning(fp_port)) { - return ROCKER_OK; - } - - info = desc_ring_fetch_desc(ring); - if (!info) { - return -ROCKER_ENOBUFS; - } - - tlv_size = rocker_tlv_total_size(sizeof(uint16_t)) + /* event type */ - rocker_tlv_total_size(0) + /* nest */ - rocker_tlv_total_size(sizeof(uint32_t)) + /* pport */ - rocker_tlv_total_size(ETH_ALEN) + /* mac addr */ - rocker_tlv_total_size(sizeof(uint16_t)); /* vlan_id */ - - if (tlv_size > desc_buf_size(info)) { - err = -ROCKER_EMSGSIZE; - goto err_too_big; - } - - buf = desc_get_buf(info, false); - if (!buf) { - err = -ROCKER_ENOMEM; - goto err_no_mem; - } - - pos = 0; - rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_TYPE, - ROCKER_TLV_EVENT_TYPE_MAC_VLAN_SEEN); - nest = rocker_tlv_nest_start(buf, &pos, ROCKER_TLV_EVENT_INFO); - rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_MAC_VLAN_PPORT, pport); - rocker_tlv_put(buf, &pos, ROCKER_TLV_EVENT_MAC_VLAN_MAC, ETH_ALEN, addr); - rocker_tlv_put_u16(buf, &pos, ROCKER_TLV_EVENT_MAC_VLAN_VLAN_ID, vlan_id); - rocker_tlv_nest_end(buf, &pos, nest); - - err = desc_set_buf(info, tlv_size); - -err_too_big: -err_no_mem: - if (desc_ring_post_desc(ring, err)) { - rocker_msix_irq(r, ROCKER_MSIX_VEC_EVENT); - } - - return err; -} - -static DescRing *rocker_get_rx_ring_by_pport(Rocker *r, - uint32_t pport) -{ - return r->rings[(pport - 1) * 2 + 3]; -} - -int rx_produce(World *world, uint32_t pport, - const struct iovec *iov, int iovcnt, uint8_t copy_to_cpu) -{ - Rocker *r = world_rocker(world); - PCIDevice *dev = (PCIDevice *)r; - DescRing *ring = rocker_get_rx_ring_by_pport(r, pport); - DescInfo *info = desc_ring_fetch_desc(ring); - char *data; - size_t data_size = iov_size(iov, iovcnt); - char *buf; - uint16_t rx_flags = 0; - uint16_t rx_csum = 0; - size_t tlv_size; - RockerTlv *tlvs[ROCKER_TLV_RX_MAX + 1]; - hwaddr frag_addr; - uint16_t frag_max_len; - int pos; - int err; - - if (!info) { - return -ROCKER_ENOBUFS; - } - - buf = desc_get_buf(info, false); - if (!buf) { - err = -ROCKER_ENXIO; - goto out; - } - rocker_tlv_parse(tlvs, ROCKER_TLV_RX_MAX, buf, desc_tlv_size(info)); - - if (!tlvs[ROCKER_TLV_RX_FRAG_ADDR] || - !tlvs[ROCKER_TLV_RX_FRAG_MAX_LEN]) { - err = -ROCKER_EINVAL; - goto out; - } - - frag_addr = rocker_tlv_get_le64(tlvs[ROCKER_TLV_RX_FRAG_ADDR]); - frag_max_len = rocker_tlv_get_le16(tlvs[ROCKER_TLV_RX_FRAG_MAX_LEN]); - - if (data_size > frag_max_len) { - err = -ROCKER_EMSGSIZE; - goto out; - } - - if (copy_to_cpu) { - rx_flags |= ROCKER_RX_FLAGS_FWD_OFFLOAD; - } - - /* XXX calc rx flags/csum */ - - tlv_size = rocker_tlv_total_size(sizeof(uint16_t)) + /* flags */ - rocker_tlv_total_size(sizeof(uint16_t)) + /* scum */ - rocker_tlv_total_size(sizeof(uint64_t)) + /* frag addr */ - rocker_tlv_total_size(sizeof(uint16_t)) + /* frag max len */ - rocker_tlv_total_size(sizeof(uint16_t)); /* frag len */ - - if (tlv_size > desc_buf_size(info)) { - err = -ROCKER_EMSGSIZE; - goto out; - } - - /* TODO: - * iov dma write can be optimized in similar way e1000 does it in - * e1000_receive_iov. But maybe if would make sense to introduce - * generic helper iov_dma_write. - */ - - data = g_malloc(data_size); - if (!data) { - err = -ROCKER_ENOMEM; - goto out; - } - iov_to_buf(iov, iovcnt, 0, data, data_size); - pci_dma_write(dev, frag_addr, data, data_size); - g_free(data); - - pos = 0; - rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_FLAGS, rx_flags); - rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_CSUM, rx_csum); - rocker_tlv_put_le64(buf, &pos, ROCKER_TLV_RX_FRAG_ADDR, frag_addr); - rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_FRAG_MAX_LEN, frag_max_len); - rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_FRAG_LEN, data_size); - - err = desc_set_buf(info, tlv_size); - -out: - if (desc_ring_post_desc(ring, err)) { - rocker_msix_irq(r, ROCKER_MSIX_VEC_RX(pport - 1)); - } - - return err; -} - -int rocker_port_eg(Rocker *r, uint32_t pport, - const struct iovec *iov, int iovcnt) -{ - FpPort *fp_port; - uint32_t port; - - if (!fp_port_from_pport(pport, &port)) { - return -ROCKER_EINVAL; - } - - fp_port = r->fp_port[port]; - - return fp_port_eg(fp_port, iov, iovcnt); -} - -static void rocker_test_dma_ctrl(Rocker *r, uint32_t val) -{ - PCIDevice *dev = PCI_DEVICE(r); - char *buf; - int i; - - buf = g_malloc(r->test_dma_size); - - if (!buf) { - DPRINTF("test dma buffer alloc failed"); - return; - } - - switch (val) { - case ROCKER_TEST_DMA_CTRL_CLEAR: - memset(buf, 0, r->test_dma_size); - break; - case ROCKER_TEST_DMA_CTRL_FILL: - memset(buf, 0x96, r->test_dma_size); - break; - case ROCKER_TEST_DMA_CTRL_INVERT: - pci_dma_read(dev, r->test_dma_addr, buf, r->test_dma_size); - for (i = 0; i < r->test_dma_size; i++) { - buf[i] = ~buf[i]; - } - break; - default: - DPRINTF("not test dma control val=0x%08x\n", val); - goto err_out; - } - pci_dma_write(dev, r->test_dma_addr, buf, r->test_dma_size); - - rocker_msix_irq(r, ROCKER_MSIX_VEC_TEST); - -err_out: - g_free(buf); -} - -static void rocker_reset(DeviceState *dev); - -static void rocker_control(Rocker *r, uint32_t val) -{ - if (val & ROCKER_CONTROL_RESET) { - rocker_reset(DEVICE(r)); - } -} - -static int rocker_pci_ring_count(Rocker *r) -{ - /* There are: - * - command ring - * - event ring - * - tx and rx ring per each port - */ - return 2 + (2 * r->fp_ports); -} - -static bool rocker_addr_is_desc_reg(Rocker *r, hwaddr addr) -{ - hwaddr start = ROCKER_DMA_DESC_BASE; - hwaddr end = start + (ROCKER_DMA_DESC_SIZE * rocker_pci_ring_count(r)); - - return addr >= start && addr < end; -} - -static void rocker_port_phys_enable_write(Rocker *r, uint64_t new) -{ - int i; - bool old_enabled; - bool new_enabled; - FpPort *fp_port; - - for (i = 0; i < r->fp_ports; i++) { - fp_port = r->fp_port[i]; - old_enabled = fp_port_enabled(fp_port); - new_enabled = (new >> (i + 1)) & 0x1; - if (new_enabled == old_enabled) { - continue; - } - if (new_enabled) { - fp_port_enable(r->fp_port[i]); - } else { - fp_port_disable(r->fp_port[i]); - } - } -} - -static void rocker_io_writel(void *opaque, hwaddr addr, uint32_t val) -{ - Rocker *r = opaque; - - if (rocker_addr_is_desc_reg(r, addr)) { - unsigned index = ROCKER_RING_INDEX(addr); - unsigned offset = addr & ROCKER_DMA_DESC_MASK; - - switch (offset) { - case ROCKER_DMA_DESC_ADDR_OFFSET: - r->lower32 = (uint64_t)val; - break; - case ROCKER_DMA_DESC_ADDR_OFFSET + 4: - desc_ring_set_base_addr(r->rings[index], - ((uint64_t)val) << 32 | r->lower32); - r->lower32 = 0; - break; - case ROCKER_DMA_DESC_SIZE_OFFSET: - desc_ring_set_size(r->rings[index], val); - break; - case ROCKER_DMA_DESC_HEAD_OFFSET: - if (desc_ring_set_head(r->rings[index], val)) { - rocker_msix_irq(r, desc_ring_get_msix_vector(r->rings[index])); - } - break; - case ROCKER_DMA_DESC_CTRL_OFFSET: - desc_ring_set_ctrl(r->rings[index], val); - break; - case ROCKER_DMA_DESC_CREDITS_OFFSET: - if (desc_ring_ret_credits(r->rings[index], val)) { - rocker_msix_irq(r, desc_ring_get_msix_vector(r->rings[index])); - } - break; - default: - DPRINTF("not implemented dma reg write(l) addr=0x" TARGET_FMT_plx - " val=0x%08x (ring %d, addr=0x%02x)\n", - addr, val, index, offset); - break; - } - return; - } - - switch (addr) { - case ROCKER_TEST_REG: - r->test_reg = val; - break; - case ROCKER_TEST_REG64: - case ROCKER_TEST_DMA_ADDR: - case ROCKER_PORT_PHYS_ENABLE: - r->lower32 = (uint64_t)val; - break; - case ROCKER_TEST_REG64 + 4: - r->test_reg64 = ((uint64_t)val) << 32 | r->lower32; - r->lower32 = 0; - break; - case ROCKER_TEST_IRQ: - rocker_msix_irq(r, val); - break; - case ROCKER_TEST_DMA_SIZE: - r->test_dma_size = val; - break; - case ROCKER_TEST_DMA_ADDR + 4: - r->test_dma_addr = ((uint64_t)val) << 32 | r->lower32; - r->lower32 = 0; - break; - case ROCKER_TEST_DMA_CTRL: - rocker_test_dma_ctrl(r, val); - break; - case ROCKER_CONTROL: - rocker_control(r, val); - break; - case ROCKER_PORT_PHYS_ENABLE + 4: - rocker_port_phys_enable_write(r, ((uint64_t)val) << 32 | r->lower32); - r->lower32 = 0; - break; - default: - DPRINTF("not implemented write(l) addr=0x" TARGET_FMT_plx - " val=0x%08x\n", addr, val); - break; - } -} - -static void rocker_io_writeq(void *opaque, hwaddr addr, uint64_t val) -{ - Rocker *r = opaque; - - if (rocker_addr_is_desc_reg(r, addr)) { - unsigned index = ROCKER_RING_INDEX(addr); - unsigned offset = addr & ROCKER_DMA_DESC_MASK; - - switch (offset) { - case ROCKER_DMA_DESC_ADDR_OFFSET: - desc_ring_set_base_addr(r->rings[index], val); - break; - default: - DPRINTF("not implemented dma reg write(q) addr=0x" TARGET_FMT_plx - " val=0x" TARGET_FMT_plx " (ring %d, offset=0x%02x)\n", - addr, val, index, offset); - break; - } - return; - } - - switch (addr) { - case ROCKER_TEST_REG64: - r->test_reg64 = val; - break; - case ROCKER_TEST_DMA_ADDR: - r->test_dma_addr = val; - break; - case ROCKER_PORT_PHYS_ENABLE: - rocker_port_phys_enable_write(r, val); - break; - default: - DPRINTF("not implemented write(q) addr=0x" TARGET_FMT_plx - " val=0x" TARGET_FMT_plx "\n", addr, val); - break; - } -} - -#ifdef DEBUG_ROCKER -#define regname(reg) case (reg): return #reg -static const char *rocker_reg_name(void *opaque, hwaddr addr) -{ - Rocker *r = opaque; - - if (rocker_addr_is_desc_reg(r, addr)) { - unsigned index = ROCKER_RING_INDEX(addr); - unsigned offset = addr & ROCKER_DMA_DESC_MASK; - static char buf[100]; - char ring_name[10]; - - switch (index) { - case 0: - sprintf(ring_name, "cmd"); - break; - case 1: - sprintf(ring_name, "event"); - break; - default: - sprintf(ring_name, "%s-%d", index % 2 ? "rx" : "tx", - (index - 2) / 2); - } - - switch (offset) { - case ROCKER_DMA_DESC_ADDR_OFFSET: - sprintf(buf, "Ring[%s] ADDR", ring_name); - return buf; - case ROCKER_DMA_DESC_ADDR_OFFSET+4: - sprintf(buf, "Ring[%s] ADDR+4", ring_name); - return buf; - case ROCKER_DMA_DESC_SIZE_OFFSET: - sprintf(buf, "Ring[%s] SIZE", ring_name); - return buf; - case ROCKER_DMA_DESC_HEAD_OFFSET: - sprintf(buf, "Ring[%s] HEAD", ring_name); - return buf; - case ROCKER_DMA_DESC_TAIL_OFFSET: - sprintf(buf, "Ring[%s] TAIL", ring_name); - return buf; - case ROCKER_DMA_DESC_CTRL_OFFSET: - sprintf(buf, "Ring[%s] CTRL", ring_name); - return buf; - case ROCKER_DMA_DESC_CREDITS_OFFSET: - sprintf(buf, "Ring[%s] CREDITS", ring_name); - return buf; - default: - sprintf(buf, "Ring[%s] ???", ring_name); - return buf; - } - } else { - switch (addr) { - regname(ROCKER_BOGUS_REG0); - regname(ROCKER_BOGUS_REG1); - regname(ROCKER_BOGUS_REG2); - regname(ROCKER_BOGUS_REG3); - regname(ROCKER_TEST_REG); - regname(ROCKER_TEST_REG64); - regname(ROCKER_TEST_REG64+4); - regname(ROCKER_TEST_IRQ); - regname(ROCKER_TEST_DMA_ADDR); - regname(ROCKER_TEST_DMA_ADDR+4); - regname(ROCKER_TEST_DMA_SIZE); - regname(ROCKER_TEST_DMA_CTRL); - regname(ROCKER_CONTROL); - regname(ROCKER_PORT_PHYS_COUNT); - regname(ROCKER_PORT_PHYS_LINK_STATUS); - regname(ROCKER_PORT_PHYS_LINK_STATUS+4); - regname(ROCKER_PORT_PHYS_ENABLE); - regname(ROCKER_PORT_PHYS_ENABLE+4); - regname(ROCKER_SWITCH_ID); - regname(ROCKER_SWITCH_ID+4); - } - } - return "???"; -} -#else -static const char *rocker_reg_name(void *opaque, hwaddr addr) -{ - return NULL; -} -#endif - -static void rocker_mmio_write(void *opaque, hwaddr addr, uint64_t val, - unsigned size) -{ - DPRINTF("Write %s addr " TARGET_FMT_plx - ", size %u, val " TARGET_FMT_plx "\n", - rocker_reg_name(opaque, addr), addr, size, val); - - switch (size) { - case 4: - rocker_io_writel(opaque, addr, val); - break; - case 8: - rocker_io_writeq(opaque, addr, val); - break; - } -} - -static uint64_t rocker_port_phys_link_status(Rocker *r) -{ - int i; - uint64_t status = 0; - - for (i = 0; i < r->fp_ports; i++) { - FpPort *port = r->fp_port[i]; - - if (fp_port_get_link_up(port)) { - status |= 1 << (i + 1); - } - } - return status; -} - -static uint64_t rocker_port_phys_enable_read(Rocker *r) -{ - int i; - uint64_t ret = 0; - - for (i = 0; i < r->fp_ports; i++) { - FpPort *port = r->fp_port[i]; - - if (fp_port_enabled(port)) { - ret |= 1 << (i + 1); - } - } - return ret; -} - -static uint32_t rocker_io_readl(void *opaque, hwaddr addr) -{ - Rocker *r = opaque; - uint32_t ret; - - if (rocker_addr_is_desc_reg(r, addr)) { - unsigned index = ROCKER_RING_INDEX(addr); - unsigned offset = addr & ROCKER_DMA_DESC_MASK; - - switch (offset) { - case ROCKER_DMA_DESC_ADDR_OFFSET: - ret = (uint32_t)desc_ring_get_base_addr(r->rings[index]); - break; - case ROCKER_DMA_DESC_ADDR_OFFSET + 4: - ret = (uint32_t)(desc_ring_get_base_addr(r->rings[index]) >> 32); - break; - case ROCKER_DMA_DESC_SIZE_OFFSET: - ret = desc_ring_get_size(r->rings[index]); - break; - case ROCKER_DMA_DESC_HEAD_OFFSET: - ret = desc_ring_get_head(r->rings[index]); - break; - case ROCKER_DMA_DESC_TAIL_OFFSET: - ret = desc_ring_get_tail(r->rings[index]); - break; - case ROCKER_DMA_DESC_CREDITS_OFFSET: - ret = desc_ring_get_credits(r->rings[index]); - break; - default: - DPRINTF("not implemented dma reg read(l) addr=0x" TARGET_FMT_plx - " (ring %d, addr=0x%02x)\n", addr, index, offset); - ret = 0; - break; - } - return ret; - } - - switch (addr) { - case ROCKER_BOGUS_REG0: - case ROCKER_BOGUS_REG1: - case ROCKER_BOGUS_REG2: - case ROCKER_BOGUS_REG3: - ret = 0xDEADBABE; - break; - case ROCKER_TEST_REG: - ret = r->test_reg * 2; - break; - case ROCKER_TEST_REG64: - ret = (uint32_t)(r->test_reg64 * 2); - break; - case ROCKER_TEST_REG64 + 4: - ret = (uint32_t)((r->test_reg64 * 2) >> 32); - break; - case ROCKER_TEST_DMA_SIZE: - ret = r->test_dma_size; - break; - case ROCKER_TEST_DMA_ADDR: - ret = (uint32_t)r->test_dma_addr; - break; - case ROCKER_TEST_DMA_ADDR + 4: - ret = (uint32_t)(r->test_dma_addr >> 32); - break; - case ROCKER_PORT_PHYS_COUNT: - ret = r->fp_ports; - break; - case ROCKER_PORT_PHYS_LINK_STATUS: - ret = (uint32_t)rocker_port_phys_link_status(r); - break; - case ROCKER_PORT_PHYS_LINK_STATUS + 4: - ret = (uint32_t)(rocker_port_phys_link_status(r) >> 32); - break; - case ROCKER_PORT_PHYS_ENABLE: - ret = (uint32_t)rocker_port_phys_enable_read(r); - break; - case ROCKER_PORT_PHYS_ENABLE + 4: - ret = (uint32_t)(rocker_port_phys_enable_read(r) >> 32); - break; - case ROCKER_SWITCH_ID: - ret = (uint32_t)r->switch_id; - break; - case ROCKER_SWITCH_ID + 4: - ret = (uint32_t)(r->switch_id >> 32); - break; - default: - DPRINTF("not implemented read(l) addr=0x" TARGET_FMT_plx "\n", addr); - ret = 0; - break; - } - return ret; -} - -static uint64_t rocker_io_readq(void *opaque, hwaddr addr) -{ - Rocker *r = opaque; - uint64_t ret; - - if (rocker_addr_is_desc_reg(r, addr)) { - unsigned index = ROCKER_RING_INDEX(addr); - unsigned offset = addr & ROCKER_DMA_DESC_MASK; - - switch (addr & ROCKER_DMA_DESC_MASK) { - case ROCKER_DMA_DESC_ADDR_OFFSET: - ret = desc_ring_get_base_addr(r->rings[index]); - break; - default: - DPRINTF("not implemented dma reg read(q) addr=0x" TARGET_FMT_plx - " (ring %d, addr=0x%02x)\n", addr, index, offset); - ret = 0; - break; - } - return ret; - } - - switch (addr) { - case ROCKER_BOGUS_REG0: - case ROCKER_BOGUS_REG2: - ret = 0xDEADBABEDEADBABEULL; - break; - case ROCKER_TEST_REG64: - ret = r->test_reg64 * 2; - break; - case ROCKER_TEST_DMA_ADDR: - ret = r->test_dma_addr; - break; - case ROCKER_PORT_PHYS_LINK_STATUS: - ret = rocker_port_phys_link_status(r); - break; - case ROCKER_PORT_PHYS_ENABLE: - ret = rocker_port_phys_enable_read(r); - break; - case ROCKER_SWITCH_ID: - ret = r->switch_id; - break; - default: - DPRINTF("not implemented read(q) addr=0x" TARGET_FMT_plx "\n", addr); - ret = 0; - break; - } - return ret; -} - -static uint64_t rocker_mmio_read(void *opaque, hwaddr addr, unsigned size) -{ - DPRINTF("Read %s addr " TARGET_FMT_plx ", size %u\n", - rocker_reg_name(opaque, addr), addr, size); - - switch (size) { - case 4: - return rocker_io_readl(opaque, addr); - case 8: - return rocker_io_readq(opaque, addr); - } - - return -1; -} - -static const MemoryRegionOps rocker_mmio_ops = { - .read = rocker_mmio_read, - .write = rocker_mmio_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 8, - }, - .impl = { - .min_access_size = 4, - .max_access_size = 8, - }, -}; - -static void rocker_msix_vectors_unuse(Rocker *r, - unsigned int num_vectors) -{ - PCIDevice *dev = PCI_DEVICE(r); - int i; - - for (i = 0; i < num_vectors; i++) { - msix_vector_unuse(dev, i); - } -} - -static int rocker_msix_vectors_use(Rocker *r, - unsigned int num_vectors) -{ - PCIDevice *dev = PCI_DEVICE(r); - int err; - int i; - - for (i = 0; i < num_vectors; i++) { - err = msix_vector_use(dev, i); - if (err) { - goto rollback; - } - } - return 0; - -rollback: - rocker_msix_vectors_unuse(r, i); - return err; -} - -static int rocker_msix_init(Rocker *r) -{ - PCIDevice *dev = PCI_DEVICE(r); - int err; - - err = msix_init(dev, ROCKER_MSIX_VEC_COUNT(r->fp_ports), - &r->msix_bar, - ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_TABLE_OFFSET, - &r->msix_bar, - ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_PBA_OFFSET, - 0); - if (err) { - return err; - } - - err = rocker_msix_vectors_use(r, ROCKER_MSIX_VEC_COUNT(r->fp_ports)); - if (err) { - goto err_msix_vectors_use; - } - - return 0; - -err_msix_vectors_use: - msix_uninit(dev, &r->msix_bar, &r->msix_bar); - return err; -} - -static void rocker_msix_uninit(Rocker *r) -{ - PCIDevice *dev = PCI_DEVICE(r); - - msix_uninit(dev, &r->msix_bar, &r->msix_bar); - rocker_msix_vectors_unuse(r, ROCKER_MSIX_VEC_COUNT(r->fp_ports)); -} - -static World *rocker_world_type_by_name(Rocker *r, const char *name) -{ - int i; - - for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) { - if (strcmp(name, world_name(r->worlds[i])) == 0) { - return r->worlds[i]; - } - } - return NULL; -} - -static int pci_rocker_init(PCIDevice *dev) -{ - Rocker *r = to_rocker(dev); - const MACAddr zero = { .a = { 0, 0, 0, 0, 0, 0 } }; - const MACAddr dflt = { .a = { 0x52, 0x54, 0x00, 0x12, 0x35, 0x01 } }; - static int sw_index; - int i, err = 0; - - /* allocate worlds */ - - r->worlds[ROCKER_WORLD_TYPE_OF_DPA] = of_dpa_world_alloc(r); - - for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) { - if (!r->worlds[i]) { - err = -ENOMEM; - goto err_world_alloc; - } - } - - if (!r->world_name) { - r->world_name = g_strdup(world_name(r->worlds[ROCKER_WORLD_TYPE_OF_DPA])); - } - - r->world_dflt = rocker_world_type_by_name(r, r->world_name); - if (!r->world_dflt) { - fprintf(stderr, - "rocker: requested world \"%s\" does not exist\n", - r->world_name); - err = -EINVAL; - goto err_world_type_by_name; - } - - /* set up memory-mapped region at BAR0 */ - - memory_region_init_io(&r->mmio, OBJECT(r), &rocker_mmio_ops, r, - "rocker-mmio", ROCKER_PCI_BAR0_SIZE); - pci_register_bar(dev, ROCKER_PCI_BAR0_IDX, - PCI_BASE_ADDRESS_SPACE_MEMORY, &r->mmio); - - /* set up memory-mapped region for MSI-X */ - - memory_region_init(&r->msix_bar, OBJECT(r), "rocker-msix-bar", - ROCKER_PCI_MSIX_BAR_SIZE); - pci_register_bar(dev, ROCKER_PCI_MSIX_BAR_IDX, - PCI_BASE_ADDRESS_SPACE_MEMORY, &r->msix_bar); - - /* MSI-X init */ - - err = rocker_msix_init(r); - if (err) { - goto err_msix_init; - } - - /* validate switch properties */ - - if (!r->name) { - r->name = g_strdup(ROCKER); - } - - if (rocker_find(r->name)) { - err = -EEXIST; - goto err_duplicate; - } - - /* Rocker name is passed in port name requests to OS with the intention - * that the name is used in interface names. Limit the length of the - * rocker name to avoid naming problems in the OS. Also, adding the - * port number as p# and unganged breakout b#, where # is at most 2 - * digits, so leave room for it too (-1 for string terminator, -3 for - * p# and -3 for b#) - */ -#define ROCKER_IFNAMSIZ 16 -#define MAX_ROCKER_NAME_LEN (ROCKER_IFNAMSIZ - 1 - 3 - 3) - if (strlen(r->name) > MAX_ROCKER_NAME_LEN) { - fprintf(stderr, - "rocker: name too long; please shorten to at most %d chars\n", - MAX_ROCKER_NAME_LEN); - return -EINVAL; - } - - if (memcmp(&r->fp_start_macaddr, &zero, sizeof(zero)) == 0) { - memcpy(&r->fp_start_macaddr, &dflt, sizeof(dflt)); - r->fp_start_macaddr.a[4] += (sw_index++); - } - - if (!r->switch_id) { - memcpy(&r->switch_id, &r->fp_start_macaddr, - sizeof(r->fp_start_macaddr)); - } - - if (r->fp_ports > ROCKER_FP_PORTS_MAX) { - r->fp_ports = ROCKER_FP_PORTS_MAX; - } - - r->rings = g_new(DescRing *, rocker_pci_ring_count(r)); - if (!r->rings) { - goto err_rings_alloc; - } - - /* Rings are ordered like this: - * - command ring - * - event ring - * - port0 tx ring - * - port0 rx ring - * - port1 tx ring - * - port1 rx ring - * ..... - */ - - err = -ENOMEM; - for (i = 0; i < rocker_pci_ring_count(r); i++) { - DescRing *ring = desc_ring_alloc(r, i); - - if (!ring) { - goto err_ring_alloc; - } - - if (i == ROCKER_RING_CMD) { - desc_ring_set_consume(ring, cmd_consume, ROCKER_MSIX_VEC_CMD); - } else if (i == ROCKER_RING_EVENT) { - desc_ring_set_consume(ring, NULL, ROCKER_MSIX_VEC_EVENT); - } else if (i % 2 == 0) { - desc_ring_set_consume(ring, tx_consume, - ROCKER_MSIX_VEC_TX((i - 2) / 2)); - } else if (i % 2 == 1) { - desc_ring_set_consume(ring, NULL, ROCKER_MSIX_VEC_RX((i - 3) / 2)); - } - - r->rings[i] = ring; - } - - for (i = 0; i < r->fp_ports; i++) { - FpPort *port = - fp_port_alloc(r, r->name, &r->fp_start_macaddr, - i, &r->fp_ports_peers[i]); - - if (!port) { - goto err_port_alloc; - } - - r->fp_port[i] = port; - fp_port_set_world(port, r->world_dflt); - } - - QLIST_INSERT_HEAD(&rockers, r, next); - - return 0; - -err_port_alloc: - for (--i; i >= 0; i--) { - FpPort *port = r->fp_port[i]; - fp_port_free(port); - } - i = rocker_pci_ring_count(r); -err_ring_alloc: - for (--i; i >= 0; i--) { - desc_ring_free(r->rings[i]); - } - g_free(r->rings); -err_rings_alloc: -err_duplicate: - rocker_msix_uninit(r); -err_msix_init: - object_unparent(OBJECT(&r->msix_bar)); - object_unparent(OBJECT(&r->mmio)); -err_world_type_by_name: -err_world_alloc: - for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) { - if (r->worlds[i]) { - world_free(r->worlds[i]); - } - } - return err; -} - -static void pci_rocker_uninit(PCIDevice *dev) -{ - Rocker *r = to_rocker(dev); - int i; - - QLIST_REMOVE(r, next); - - for (i = 0; i < r->fp_ports; i++) { - FpPort *port = r->fp_port[i]; - - fp_port_free(port); - r->fp_port[i] = NULL; - } - - for (i = 0; i < rocker_pci_ring_count(r); i++) { - if (r->rings[i]) { - desc_ring_free(r->rings[i]); - } - } - g_free(r->rings); - - rocker_msix_uninit(r); - object_unparent(OBJECT(&r->msix_bar)); - object_unparent(OBJECT(&r->mmio)); - - for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) { - if (r->worlds[i]) { - world_free(r->worlds[i]); - } - } - g_free(r->fp_ports_peers); -} - -static void rocker_reset(DeviceState *dev) -{ - Rocker *r = to_rocker(dev); - int i; - - for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) { - if (r->worlds[i]) { - world_reset(r->worlds[i]); - } - } - for (i = 0; i < r->fp_ports; i++) { - fp_port_reset(r->fp_port[i]); - fp_port_set_world(r->fp_port[i], r->world_dflt); - } - - r->test_reg = 0; - r->test_reg64 = 0; - r->test_dma_addr = 0; - r->test_dma_size = 0; - - for (i = 0; i < rocker_pci_ring_count(r); i++) { - desc_ring_reset(r->rings[i]); - } - - DPRINTF("Reset done\n"); -} - -static Property rocker_properties[] = { - DEFINE_PROP_STRING("name", Rocker, name), - DEFINE_PROP_STRING("world", Rocker, world_name), - DEFINE_PROP_MACADDR("fp_start_macaddr", Rocker, - fp_start_macaddr), - DEFINE_PROP_UINT64("switch_id", Rocker, - switch_id, 0), - DEFINE_PROP_ARRAY("ports", Rocker, fp_ports, - fp_ports_peers, qdev_prop_netdev, NICPeers), - DEFINE_PROP_END_OF_LIST(), -}; - -static const VMStateDescription rocker_vmsd = { - .name = ROCKER, - .unmigratable = 1, -}; - -static void rocker_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->init = pci_rocker_init; - k->exit = pci_rocker_uninit; - k->vendor_id = PCI_VENDOR_ID_REDHAT; - k->device_id = PCI_DEVICE_ID_REDHAT_ROCKER; - k->revision = ROCKER_PCI_REVISION; - k->class_id = PCI_CLASS_NETWORK_OTHER; - set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); - dc->desc = "Rocker Switch"; - dc->reset = rocker_reset; - dc->props = rocker_properties; - dc->vmsd = &rocker_vmsd; -} - -static const TypeInfo rocker_info = { - .name = ROCKER, - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(Rocker), - .class_init = rocker_class_init, -}; - -static void rocker_register_types(void) -{ - type_register_static(&rocker_info); -} - -type_init(rocker_register_types) diff --git a/qemu/hw/net/rocker/rocker.h b/qemu/hw/net/rocker/rocker.h deleted file mode 100644 index f9c80f801..000000000 --- a/qemu/hw/net/rocker/rocker.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * QEMU rocker switch emulation - * - * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com> - * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us> - * Copyright (c) 2014 Neil Horman <nhorman@tuxdriver.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _ROCKER_H_ -#define _ROCKER_H_ - -#include "qemu/sockets.h" - -#if defined(DEBUG_ROCKER) -# define DPRINTF(fmt, ...) \ - do { \ - struct timeval tv; \ - char timestr[64]; \ - time_t now; \ - gettimeofday(&tv, NULL); \ - now = tv.tv_sec; \ - strftime(timestr, sizeof(timestr), "%T", localtime(&now)); \ - fprintf(stderr, "%s.%06ld ", timestr, tv.tv_usec); \ - fprintf(stderr, "ROCKER: " fmt, ## __VA_ARGS__); \ - } while (0) -#else -static inline GCC_FMT_ATTR(1, 2) int DPRINTF(const char *fmt, ...) -{ - return 0; -} -#endif - -#define __le16 uint16_t -#define __le32 uint32_t -#define __le64 uint64_t - -#define __be16 uint16_t -#define __be32 uint32_t -#define __be64 uint64_t - -static inline bool ipv4_addr_is_multicast(__be32 addr) -{ - return (addr & htonl(0xf0000000)) == htonl(0xe0000000); -} - -typedef struct ipv6_addr { - union { - uint8_t addr8[16]; - __be16 addr16[8]; - __be32 addr32[4]; - }; -} Ipv6Addr; - -static inline bool ipv6_addr_is_multicast(const Ipv6Addr *addr) -{ - return (addr->addr32[0] & htonl(0xFF000000)) == htonl(0xFF000000); -} - -typedef struct rocker Rocker; -typedef struct world World; -typedef struct desc_info DescInfo; -typedef struct desc_ring DescRing; - -Rocker *rocker_find(const char *name); -uint32_t rocker_fp_ports(Rocker *r); -int rocker_event_link_changed(Rocker *r, uint32_t pport, bool link_up); -int rocker_event_mac_vlan_seen(Rocker *r, uint32_t pport, uint8_t *addr, - uint16_t vlan_id); -int rx_produce(World *world, uint32_t pport, - const struct iovec *iov, int iovcnt, uint8_t copy_to_cpu); -int rocker_port_eg(Rocker *r, uint32_t pport, - const struct iovec *iov, int iovcnt); - -#endif /* _ROCKER_H_ */ diff --git a/qemu/hw/net/rocker/rocker_desc.c b/qemu/hw/net/rocker/rocker_desc.c deleted file mode 100644 index ac02797b7..000000000 --- a/qemu/hw/net/rocker/rocker_desc.c +++ /dev/null @@ -1,374 +0,0 @@ -/* - * QEMU rocker switch emulation - Descriptor ring support - * - * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "qemu/osdep.h" -#include "net/net.h" -#include "hw/hw.h" -#include "hw/pci/pci.h" - -#include "rocker.h" -#include "rocker_hw.h" -#include "rocker_desc.h" - -struct desc_ring { - hwaddr base_addr; - uint32_t size; - uint32_t head; - uint32_t tail; - uint32_t ctrl; - uint32_t credits; - Rocker *r; - DescInfo *info; - int index; - desc_ring_consume *consume; - unsigned msix_vector; -}; - -struct desc_info { - DescRing *ring; - RockerDesc desc; - char *buf; - size_t buf_size; -}; - -uint16_t desc_buf_size(DescInfo *info) -{ - return le16_to_cpu(info->desc.buf_size); -} - -uint16_t desc_tlv_size(DescInfo *info) -{ - return le16_to_cpu(info->desc.tlv_size); -} - -char *desc_get_buf(DescInfo *info, bool read_only) -{ - PCIDevice *dev = PCI_DEVICE(info->ring->r); - size_t size = read_only ? le16_to_cpu(info->desc.tlv_size) : - le16_to_cpu(info->desc.buf_size); - - if (size > info->buf_size) { - info->buf = g_realloc(info->buf, size); - info->buf_size = size; - } - - if (!info->buf) { - return NULL; - } - - if (pci_dma_read(dev, le64_to_cpu(info->desc.buf_addr), info->buf, size)) { - return NULL; - } - - return info->buf; -} - -int desc_set_buf(DescInfo *info, size_t tlv_size) -{ - PCIDevice *dev = PCI_DEVICE(info->ring->r); - - if (tlv_size > info->buf_size) { - DPRINTF("ERROR: trying to write more to desc buf than it " - "can hold buf_size %zu tlv_size %zu\n", - info->buf_size, tlv_size); - return -ROCKER_EMSGSIZE; - } - - info->desc.tlv_size = cpu_to_le16(tlv_size); - pci_dma_write(dev, le64_to_cpu(info->desc.buf_addr), info->buf, tlv_size); - - return ROCKER_OK; -} - -DescRing *desc_get_ring(DescInfo *info) -{ - return info->ring; -} - -int desc_ring_index(DescRing *ring) -{ - return ring->index; -} - -static bool desc_ring_empty(DescRing *ring) -{ - return ring->head == ring->tail; -} - -bool desc_ring_set_base_addr(DescRing *ring, uint64_t base_addr) -{ - if (base_addr & 0x7) { - DPRINTF("ERROR: ring[%d] desc base addr (0x" TARGET_FMT_plx - ") not 8-byte aligned\n", ring->index, base_addr); - return false; - } - - ring->base_addr = base_addr; - - return true; -} - -uint64_t desc_ring_get_base_addr(DescRing *ring) -{ - return ring->base_addr; -} - -bool desc_ring_set_size(DescRing *ring, uint32_t size) -{ - int i; - - if (size < 2 || size > 0x10000 || (size & (size - 1))) { - DPRINTF("ERROR: ring[%d] size (%d) not a power of 2 " - "or in range [2, 64K]\n", ring->index, size); - return false; - } - - for (i = 0; i < ring->size; i++) { - g_free(ring->info[i].buf); - } - - ring->size = size; - ring->head = ring->tail = 0; - - ring->info = g_renew(DescInfo, ring->info, size); - if (!ring->info) { - return false; - } - - memset(ring->info, 0, size * sizeof(DescInfo)); - - for (i = 0; i < size; i++) { - ring->info[i].ring = ring; - } - - return true; -} - -uint32_t desc_ring_get_size(DescRing *ring) -{ - return ring->size; -} - -static DescInfo *desc_read(DescRing *ring, uint32_t index) -{ - PCIDevice *dev = PCI_DEVICE(ring->r); - DescInfo *info = &ring->info[index]; - hwaddr addr = ring->base_addr + (sizeof(RockerDesc) * index); - - pci_dma_read(dev, addr, &info->desc, sizeof(info->desc)); - - return info; -} - -static void desc_write(DescRing *ring, uint32_t index) -{ - PCIDevice *dev = PCI_DEVICE(ring->r); - DescInfo *info = &ring->info[index]; - hwaddr addr = ring->base_addr + (sizeof(RockerDesc) * index); - - pci_dma_write(dev, addr, &info->desc, sizeof(info->desc)); -} - -static bool desc_ring_base_addr_check(DescRing *ring) -{ - if (!ring->base_addr) { - DPRINTF("ERROR: ring[%d] not-initialized desc base address!\n", - ring->index); - return false; - } - return true; -} - -static DescInfo *__desc_ring_fetch_desc(DescRing *ring) -{ - return desc_read(ring, ring->tail); -} - -DescInfo *desc_ring_fetch_desc(DescRing *ring) -{ - if (desc_ring_empty(ring) || !desc_ring_base_addr_check(ring)) { - return NULL; - } - - return desc_read(ring, ring->tail); -} - -static bool __desc_ring_post_desc(DescRing *ring, int err) -{ - uint16_t comp_err = 0x8000 | (uint16_t)-err; - DescInfo *info = &ring->info[ring->tail]; - - info->desc.comp_err = cpu_to_le16(comp_err); - desc_write(ring, ring->tail); - ring->tail = (ring->tail + 1) % ring->size; - - /* return true if starting credit count */ - - return ring->credits++ == 0; -} - -bool desc_ring_post_desc(DescRing *ring, int err) -{ - if (desc_ring_empty(ring)) { - DPRINTF("ERROR: ring[%d] trying to post desc to empty ring\n", - ring->index); - return false; - } - - if (!desc_ring_base_addr_check(ring)) { - return false; - } - - return __desc_ring_post_desc(ring, err); -} - -static bool ring_pump(DescRing *ring) -{ - DescInfo *info; - bool primed = false; - int err; - - /* If the ring has a consumer, call consumer for each - * desc starting at tail and stopping when tail reaches - * head (the empty ring condition). - */ - - if (ring->consume) { - while (ring->head != ring->tail) { - info = __desc_ring_fetch_desc(ring); - err = ring->consume(ring->r, info); - if (__desc_ring_post_desc(ring, err)) { - primed = true; - } - } - } - - return primed; -} - -bool desc_ring_set_head(DescRing *ring, uint32_t new) -{ - uint32_t tail = ring->tail; - uint32_t head = ring->head; - - if (!desc_ring_base_addr_check(ring)) { - return false; - } - - if (new >= ring->size) { - DPRINTF("ERROR: trying to set head (%d) past ring[%d] size (%d)\n", - new, ring->index, ring->size); - return false; - } - - if (((head < tail) && ((new >= tail) || (new < head))) || - ((head > tail) && ((new >= tail) && (new < head)))) { - DPRINTF("ERROR: trying to wrap ring[%d] " - "(head %d, tail %d, new head %d)\n", - ring->index, head, tail, new); - return false; - } - - if (new == ring->head) { - DPRINTF("WARNING: setting head (%d) to current head position\n", new); - } - - ring->head = new; - - return ring_pump(ring); -} - -uint32_t desc_ring_get_head(DescRing *ring) -{ - return ring->head; -} - -uint32_t desc_ring_get_tail(DescRing *ring) -{ - return ring->tail; -} - -void desc_ring_set_ctrl(DescRing *ring, uint32_t val) -{ - if (val & ROCKER_DMA_DESC_CTRL_RESET) { - DPRINTF("ring[%d] resetting\n", ring->index); - desc_ring_reset(ring); - } -} - -bool desc_ring_ret_credits(DescRing *ring, uint32_t credits) -{ - if (credits > ring->credits) { - DPRINTF("ERROR: trying to return more credits (%d) " - "than are outstanding (%d)\n", credits, ring->credits); - ring->credits = 0; - return false; - } - - ring->credits -= credits; - - /* return true if credits are still outstanding */ - - return ring->credits > 0; -} - -uint32_t desc_ring_get_credits(DescRing *ring) -{ - return ring->credits; -} - -void desc_ring_set_consume(DescRing *ring, desc_ring_consume *consume, - unsigned vector) -{ - ring->consume = consume; - ring->msix_vector = vector; -} - -unsigned desc_ring_get_msix_vector(DescRing *ring) -{ - return ring->msix_vector; -} - -DescRing *desc_ring_alloc(Rocker *r, int index) -{ - DescRing *ring; - - ring = g_new0(DescRing, 1); - if (!ring) { - return NULL; - } - - ring->r = r; - ring->index = index; - - return ring; -} - -void desc_ring_free(DescRing *ring) -{ - g_free(ring->info); - g_free(ring); -} - -void desc_ring_reset(DescRing *ring) -{ - ring->base_addr = 0; - ring->size = 0; - ring->head = 0; - ring->tail = 0; - ring->ctrl = 0; - ring->credits = 0; -} diff --git a/qemu/hw/net/rocker/rocker_desc.h b/qemu/hw/net/rocker/rocker_desc.h deleted file mode 100644 index d4041f5c4..000000000 --- a/qemu/hw/net/rocker/rocker_desc.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * QEMU rocker switch emulation - Descriptor ring support - * - * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - - -#ifndef _ROCKER_DESC_H_ -#define _ROCKER_DESC_H_ - -#include "rocker_hw.h" - -typedef int (desc_ring_consume)(Rocker *r, DescInfo *info); - -uint16_t desc_buf_size(DescInfo *info); -uint16_t desc_tlv_size(DescInfo *info); -char *desc_get_buf(DescInfo *info, bool read_only); -int desc_set_buf(DescInfo *info, size_t tlv_size); -DescRing *desc_get_ring(DescInfo *info); - -int desc_ring_index(DescRing *ring); -bool desc_ring_set_base_addr(DescRing *ring, uint64_t base_addr); -uint64_t desc_ring_get_base_addr(DescRing *ring); -bool desc_ring_set_size(DescRing *ring, uint32_t size); -uint32_t desc_ring_get_size(DescRing *ring); -bool desc_ring_set_head(DescRing *ring, uint32_t new); -uint32_t desc_ring_get_head(DescRing *ring); -uint32_t desc_ring_get_tail(DescRing *ring); -void desc_ring_set_ctrl(DescRing *ring, uint32_t val); -bool desc_ring_ret_credits(DescRing *ring, uint32_t credits); -uint32_t desc_ring_get_credits(DescRing *ring); - -DescInfo *desc_ring_fetch_desc(DescRing *ring); -bool desc_ring_post_desc(DescRing *ring, int status); - -void desc_ring_set_consume(DescRing *ring, desc_ring_consume *consume, - unsigned vector); -unsigned desc_ring_get_msix_vector(DescRing *ring); -DescRing *desc_ring_alloc(Rocker *r, int index); -void desc_ring_free(DescRing *ring); -void desc_ring_reset(DescRing *ring); - -#endif diff --git a/qemu/hw/net/rocker/rocker_fp.c b/qemu/hw/net/rocker/rocker_fp.c deleted file mode 100644 index 0149899c6..000000000 --- a/qemu/hw/net/rocker/rocker_fp.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * QEMU rocker switch emulation - front-panel ports - * - * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "qemu/osdep.h" -#include "net/clients.h" - -#include "rocker.h" -#include "rocker_hw.h" -#include "rocker_fp.h" -#include "rocker_world.h" - -enum duplex { - DUPLEX_HALF = 0, - DUPLEX_FULL -}; - -struct fp_port { - Rocker *r; - World *world; - unsigned int index; - char *name; - uint32_t pport; - bool enabled; - uint32_t speed; - uint8_t duplex; - uint8_t autoneg; - uint8_t learning; - NICState *nic; - NICConf conf; -}; - -char *fp_port_get_name(FpPort *port) -{ - return port->name; -} - -bool fp_port_get_link_up(FpPort *port) -{ - return !qemu_get_queue(port->nic)->link_down; -} - -void fp_port_get_info(FpPort *port, RockerPortList *info) -{ - info->value->name = g_strdup(port->name); - info->value->enabled = port->enabled; - info->value->link_up = fp_port_get_link_up(port); - info->value->speed = port->speed; - info->value->duplex = port->duplex; - info->value->autoneg = port->autoneg; -} - -void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr) -{ - memcpy(macaddr->a, port->conf.macaddr.a, sizeof(macaddr->a)); -} - -void fp_port_set_macaddr(FpPort *port, MACAddr *macaddr) -{ -/* XXX TODO implement and test setting mac addr - * XXX memcpy(port->conf.macaddr.a, macaddr.a, sizeof(port->conf.macaddr.a)); - */ -} - -uint8_t fp_port_get_learning(FpPort *port) -{ - return port->learning; -} - -void fp_port_set_learning(FpPort *port, uint8_t learning) -{ - port->learning = learning; -} - -int fp_port_get_settings(FpPort *port, uint32_t *speed, - uint8_t *duplex, uint8_t *autoneg) -{ - *speed = port->speed; - *duplex = port->duplex; - *autoneg = port->autoneg; - - return ROCKER_OK; -} - -int fp_port_set_settings(FpPort *port, uint32_t speed, - uint8_t duplex, uint8_t autoneg) -{ - /* XXX validate inputs */ - - port->speed = speed; - port->duplex = duplex; - port->autoneg = autoneg; - - return ROCKER_OK; -} - -bool fp_port_from_pport(uint32_t pport, uint32_t *port) -{ - if (pport < 1 || pport > ROCKER_FP_PORTS_MAX) { - return false; - } - *port = pport - 1; - return true; -} - -int fp_port_eg(FpPort *port, const struct iovec *iov, int iovcnt) -{ - NetClientState *nc = qemu_get_queue(port->nic); - - if (port->enabled) { - qemu_sendv_packet(nc, iov, iovcnt); - } - - return ROCKER_OK; -} - -static ssize_t fp_port_receive_iov(NetClientState *nc, const struct iovec *iov, - int iovcnt) -{ - FpPort *port = qemu_get_nic_opaque(nc); - - /* If the port is disabled, we want to drop this pkt - * now rather than queing it for later. We don't want - * any stale pkts getting into the device when the port - * transitions to enabled. - */ - - if (!port->enabled) { - return -1; - } - - return world_ingress(port->world, port->pport, iov, iovcnt); -} - -static ssize_t fp_port_receive(NetClientState *nc, const uint8_t *buf, - size_t size) -{ - const struct iovec iov = { - .iov_base = (uint8_t *)buf, - .iov_len = size - }; - - return fp_port_receive_iov(nc, &iov, 1); -} - -static void fp_port_cleanup(NetClientState *nc) -{ -} - -static void fp_port_set_link_status(NetClientState *nc) -{ - FpPort *port = qemu_get_nic_opaque(nc); - - rocker_event_link_changed(port->r, port->pport, !nc->link_down); -} - -static NetClientInfo fp_port_info = { - .type = NET_CLIENT_OPTIONS_KIND_NIC, - .size = sizeof(NICState), - .receive = fp_port_receive, - .receive_iov = fp_port_receive_iov, - .cleanup = fp_port_cleanup, - .link_status_changed = fp_port_set_link_status, -}; - -World *fp_port_get_world(FpPort *port) -{ - return port->world; -} - -void fp_port_set_world(FpPort *port, World *world) -{ - DPRINTF("port %d setting world \"%s\"\n", port->index, world_name(world)); - port->world = world; -} - -bool fp_port_check_world(FpPort *port, World *world) -{ - return port->world == world; -} - -bool fp_port_enabled(FpPort *port) -{ - return port->enabled; -} - -static void fp_port_set_link(FpPort *port, bool up) -{ - NetClientState *nc = qemu_get_queue(port->nic); - - if (up == nc->link_down) { - nc->link_down = !up; - nc->info->link_status_changed(nc); - } -} - -void fp_port_enable(FpPort *port) -{ - fp_port_set_link(port, true); - port->enabled = true; - DPRINTF("port %d enabled\n", port->index); -} - -void fp_port_disable(FpPort *port) -{ - port->enabled = false; - fp_port_set_link(port, false); - DPRINTF("port %d disabled\n", port->index); -} - -FpPort *fp_port_alloc(Rocker *r, char *sw_name, - MACAddr *start_mac, unsigned int index, - NICPeers *peers) -{ - FpPort *port = g_new0(FpPort, 1); - - if (!port) { - return NULL; - } - - port->r = r; - port->index = index; - port->pport = index + 1; - - /* front-panel switch port names are 1-based */ - - port->name = g_strdup_printf("%sp%d", sw_name, port->pport); - - memcpy(port->conf.macaddr.a, start_mac, sizeof(port->conf.macaddr.a)); - port->conf.macaddr.a[5] += index; - port->conf.bootindex = -1; - port->conf.peers = *peers; - - port->nic = qemu_new_nic(&fp_port_info, &port->conf, - sw_name, NULL, port); - qemu_format_nic_info_str(qemu_get_queue(port->nic), - port->conf.macaddr.a); - - fp_port_reset(port); - - return port; -} - -void fp_port_free(FpPort *port) -{ - qemu_del_nic(port->nic); - g_free(port->name); - g_free(port); -} - -void fp_port_reset(FpPort *port) -{ - fp_port_disable(port); - port->speed = 10000; /* 10Gbps */ - port->duplex = DUPLEX_FULL; - port->autoneg = 0; -} diff --git a/qemu/hw/net/rocker/rocker_fp.h b/qemu/hw/net/rocker/rocker_fp.h deleted file mode 100644 index 04592bbfd..000000000 --- a/qemu/hw/net/rocker/rocker_fp.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * QEMU rocker switch emulation - front-panel ports - * - * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _ROCKER_FP_H_ -#define _ROCKER_FP_H_ - -#include "net/net.h" -#include "qemu/iov.h" - -#define ROCKER_FP_PORTS_MAX 62 - -typedef struct fp_port FpPort; - -int fp_port_eg(FpPort *port, const struct iovec *iov, int iovcnt); - -char *fp_port_get_name(FpPort *port); -bool fp_port_get_link_up(FpPort *port); -void fp_port_get_info(FpPort *port, RockerPortList *info); -void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr); -void fp_port_set_macaddr(FpPort *port, MACAddr *macaddr); -uint8_t fp_port_get_learning(FpPort *port); -void fp_port_set_learning(FpPort *port, uint8_t learning); -int fp_port_get_settings(FpPort *port, uint32_t *speed, - uint8_t *duplex, uint8_t *autoneg); -int fp_port_set_settings(FpPort *port, uint32_t speed, - uint8_t duplex, uint8_t autoneg); -bool fp_port_from_pport(uint32_t pport, uint32_t *port); -World *fp_port_get_world(FpPort *port); -void fp_port_set_world(FpPort *port, World *world); -bool fp_port_check_world(FpPort *port, World *world); -bool fp_port_enabled(FpPort *port); -void fp_port_enable(FpPort *port); -void fp_port_disable(FpPort *port); - -FpPort *fp_port_alloc(Rocker *r, char *sw_name, - MACAddr *start_mac, unsigned int index, - NICPeers *peers); -void fp_port_free(FpPort *port); -void fp_port_reset(FpPort *port); - -#endif /* _ROCKER_FP_H_ */ diff --git a/qemu/hw/net/rocker/rocker_hw.h b/qemu/hw/net/rocker/rocker_hw.h deleted file mode 100644 index 8c5083032..000000000 --- a/qemu/hw/net/rocker/rocker_hw.h +++ /dev/null @@ -1,493 +0,0 @@ -/* - * Rocker switch hardware register and descriptor definitions. - * - * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com> - * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us> - * - */ - -#ifndef _ROCKER_HW_ -#define _ROCKER_HW_ - -#define __le16 uint16_t -#define __le32 uint32_t -#define __le64 uint64_t - -/* - * Return codes - */ - -enum { - ROCKER_OK = 0, - ROCKER_ENOENT = 2, - ROCKER_ENXIO = 6, - ROCKER_ENOMEM = 12, - ROCKER_EEXIST = 17, - ROCKER_EINVAL = 22, - ROCKER_EMSGSIZE = 90, - ROCKER_ENOTSUP = 95, - ROCKER_ENOBUFS = 105, -}; - -/* - * PCI configuration space - */ - -#define ROCKER_PCI_REVISION 0x1 -#define ROCKER_PCI_BAR0_IDX 0 -#define ROCKER_PCI_BAR0_SIZE 0x2000 -#define ROCKER_PCI_MSIX_BAR_IDX 1 -#define ROCKER_PCI_MSIX_BAR_SIZE 0x2000 -#define ROCKER_PCI_MSIX_TABLE_OFFSET 0x0000 -#define ROCKER_PCI_MSIX_PBA_OFFSET 0x1000 - -/* - * MSI-X vectors - */ - -enum { - ROCKER_MSIX_VEC_CMD, - ROCKER_MSIX_VEC_EVENT, - ROCKER_MSIX_VEC_TEST, - ROCKER_MSIX_VEC_RESERVED0, - __ROCKER_MSIX_VEC_TX, - __ROCKER_MSIX_VEC_RX, -#define ROCKER_MSIX_VEC_TX(port) \ - (__ROCKER_MSIX_VEC_TX + ((port) * 2)) -#define ROCKER_MSIX_VEC_RX(port) \ - (__ROCKER_MSIX_VEC_RX + ((port) * 2)) -#define ROCKER_MSIX_VEC_COUNT(portcnt) \ - (ROCKER_MSIX_VEC_RX((portcnt) - 1) + 1) -}; - -/* - * Rocker bogus registers - */ -#define ROCKER_BOGUS_REG0 0x0000 -#define ROCKER_BOGUS_REG1 0x0004 -#define ROCKER_BOGUS_REG2 0x0008 -#define ROCKER_BOGUS_REG3 0x000c - -/* - * Rocker test registers - */ -#define ROCKER_TEST_REG 0x0010 -#define ROCKER_TEST_REG64 0x0018 /* 8-byte */ -#define ROCKER_TEST_IRQ 0x0020 -#define ROCKER_TEST_DMA_ADDR 0x0028 /* 8-byte */ -#define ROCKER_TEST_DMA_SIZE 0x0030 -#define ROCKER_TEST_DMA_CTRL 0x0034 - -/* - * Rocker test register ctrl - */ -#define ROCKER_TEST_DMA_CTRL_CLEAR (1 << 0) -#define ROCKER_TEST_DMA_CTRL_FILL (1 << 1) -#define ROCKER_TEST_DMA_CTRL_INVERT (1 << 2) - -/* - * Rocker DMA ring register offsets - */ -#define ROCKER_DMA_DESC_BASE 0x1000 -#define ROCKER_DMA_DESC_SIZE 32 -#define ROCKER_DMA_DESC_MASK 0x1F -#define ROCKER_DMA_DESC_TOTAL_SIZE \ - (ROCKER_DMA_DESC_SIZE * 64) /* 62 ports + event + cmd */ -#define ROCKER_DMA_DESC_ADDR_OFFSET 0x00 /* 8-byte */ -#define ROCKER_DMA_DESC_SIZE_OFFSET 0x08 -#define ROCKER_DMA_DESC_HEAD_OFFSET 0x0c -#define ROCKER_DMA_DESC_TAIL_OFFSET 0x10 -#define ROCKER_DMA_DESC_CTRL_OFFSET 0x14 -#define ROCKER_DMA_DESC_CREDITS_OFFSET 0x18 -#define ROCKER_DMA_DESC_RSVD_OFFSET 0x1c - -/* - * Rocker dma ctrl register bits - */ -#define ROCKER_DMA_DESC_CTRL_RESET (1 << 0) - -/* - * Rocker ring indices - */ -#define ROCKER_RING_CMD 0 -#define ROCKER_RING_EVENT 1 - -/* - * Helper macro to do convert a dma ring register - * to its index. Based on the fact that the register - * group stride is 32 bytes. - */ -#define ROCKER_RING_INDEX(reg) ((reg >> 5) & 0x7F) - -/* - * Rocker DMA Descriptor - */ - -typedef struct rocker_desc { - __le64 buf_addr; - uint64_t cookie; - __le16 buf_size; - __le16 tlv_size; - __le16 rsvd[5]; /* pad to 32 bytes */ - __le16 comp_err; -} __attribute__((packed, aligned(8))) RockerDesc; - -/* - * Rocker TLV type fields - */ - -typedef struct rocker_tlv { - __le32 type; - __le16 len; - __le16 rsvd; -} __attribute__((packed, aligned(8))) RockerTlv; - -/* cmd msg */ -enum { - ROCKER_TLV_CMD_UNSPEC, - ROCKER_TLV_CMD_TYPE, /* u16 */ - ROCKER_TLV_CMD_INFO, /* nest */ - - __ROCKER_TLV_CMD_MAX, - ROCKER_TLV_CMD_MAX = __ROCKER_TLV_CMD_MAX - 1, -}; - -enum { - ROCKER_TLV_CMD_TYPE_UNSPEC, - ROCKER_TLV_CMD_TYPE_GET_PORT_SETTINGS, - ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS, - ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD, - ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD, - ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL, - ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_GET_STATS, - ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD, - ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD, - ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL, - ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS, - - __ROCKER_TLV_CMD_TYPE_MAX, - ROCKER_TLV_CMD_TYPE_MAX = __ROCKER_TLV_CMD_TYPE_MAX - 1, -}; - -/* cmd info nested for set/get port settings */ -enum { - ROCKER_TLV_CMD_PORT_SETTINGS_UNSPEC, - ROCKER_TLV_CMD_PORT_SETTINGS_PPORT, /* u32 */ - ROCKER_TLV_CMD_PORT_SETTINGS_SPEED, /* u32 */ - ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX, /* u8 */ - ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG, /* u8 */ - ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR, /* binary */ - ROCKER_TLV_CMD_PORT_SETTINGS_MODE, /* u8 */ - ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING, /* u8 */ - ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME, /* binary */ - - __ROCKER_TLV_CMD_PORT_SETTINGS_MAX, - ROCKER_TLV_CMD_PORT_SETTINGS_MAX = __ROCKER_TLV_CMD_PORT_SETTINGS_MAX - 1, -}; - -enum { - ROCKER_PORT_MODE_OF_DPA, -}; - -/* event msg */ -enum { - ROCKER_TLV_EVENT_UNSPEC, - ROCKER_TLV_EVENT_TYPE, /* u16 */ - ROCKER_TLV_EVENT_INFO, /* nest */ - - __ROCKER_TLV_EVENT_MAX, - ROCKER_TLV_EVENT_MAX = __ROCKER_TLV_EVENT_MAX - 1, -}; - -enum { - ROCKER_TLV_EVENT_TYPE_UNSPEC, - ROCKER_TLV_EVENT_TYPE_LINK_CHANGED, - ROCKER_TLV_EVENT_TYPE_MAC_VLAN_SEEN, - - __ROCKER_TLV_EVENT_TYPE_MAX, - ROCKER_TLV_EVENT_TYPE_MAX = __ROCKER_TLV_EVENT_TYPE_MAX - 1, -}; - -/* event info nested for link changed */ -enum { - ROCKER_TLV_EVENT_LINK_CHANGED_UNSPEC, - ROCKER_TLV_EVENT_LINK_CHANGED_PPORT, /* u32 */ - ROCKER_TLV_EVENT_LINK_CHANGED_LINKUP, /* u8 */ - - __ROCKER_TLV_EVENT_LINK_CHANGED_MAX, - ROCKER_TLV_EVENT_LINK_CHANGED_MAX = __ROCKER_TLV_EVENT_LINK_CHANGED_MAX - 1, -}; - -/* event info nested for MAC/VLAN */ -enum { - ROCKER_TLV_EVENT_MAC_VLAN_UNSPEC, - ROCKER_TLV_EVENT_MAC_VLAN_PPORT, /* u32 */ - ROCKER_TLV_EVENT_MAC_VLAN_MAC, /* binary */ - ROCKER_TLV_EVENT_MAC_VLAN_VLAN_ID, /* __be16 */ - - __ROCKER_TLV_EVENT_MAC_VLAN_MAX, - ROCKER_TLV_EVENT_MAC_VLAN_MAX = __ROCKER_TLV_EVENT_MAC_VLAN_MAX - 1, -}; - -/* Rx msg */ -enum { - ROCKER_TLV_RX_UNSPEC, - ROCKER_TLV_RX_FLAGS, /* u16, see RX_FLAGS_ */ - ROCKER_TLV_RX_CSUM, /* u16 */ - ROCKER_TLV_RX_FRAG_ADDR, /* u64 */ - ROCKER_TLV_RX_FRAG_MAX_LEN, /* u16 */ - ROCKER_TLV_RX_FRAG_LEN, /* u16 */ - - __ROCKER_TLV_RX_MAX, - ROCKER_TLV_RX_MAX = __ROCKER_TLV_RX_MAX - 1, -}; - -#define ROCKER_RX_FLAGS_IPV4 (1 << 0) -#define ROCKER_RX_FLAGS_IPV6 (1 << 1) -#define ROCKER_RX_FLAGS_CSUM_CALC (1 << 2) -#define ROCKER_RX_FLAGS_IPV4_CSUM_GOOD (1 << 3) -#define ROCKER_RX_FLAGS_IP_FRAG (1 << 4) -#define ROCKER_RX_FLAGS_TCP (1 << 5) -#define ROCKER_RX_FLAGS_UDP (1 << 6) -#define ROCKER_RX_FLAGS_TCP_UDP_CSUM_GOOD (1 << 7) -#define ROCKER_RX_FLAGS_FWD_OFFLOAD (1 << 8) - -/* Tx msg */ -enum { - ROCKER_TLV_TX_UNSPEC, - ROCKER_TLV_TX_OFFLOAD, /* u8, see TX_OFFLOAD_ */ - ROCKER_TLV_TX_L3_CSUM_OFF, /* u16 */ - ROCKER_TLV_TX_TSO_MSS, /* u16 */ - ROCKER_TLV_TX_TSO_HDR_LEN, /* u16 */ - ROCKER_TLV_TX_FRAGS, /* array */ - - __ROCKER_TLV_TX_MAX, - ROCKER_TLV_TX_MAX = __ROCKER_TLV_TX_MAX - 1, -}; - -#define ROCKER_TX_OFFLOAD_NONE 0 -#define ROCKER_TX_OFFLOAD_IP_CSUM 1 -#define ROCKER_TX_OFFLOAD_TCP_UDP_CSUM 2 -#define ROCKER_TX_OFFLOAD_L3_CSUM 3 -#define ROCKER_TX_OFFLOAD_TSO 4 - -#define ROCKER_TX_FRAGS_MAX 16 - -enum { - ROCKER_TLV_TX_FRAG_UNSPEC, - ROCKER_TLV_TX_FRAG, /* nest */ - - __ROCKER_TLV_TX_FRAG_MAX, - ROCKER_TLV_TX_FRAG_MAX = __ROCKER_TLV_TX_FRAG_MAX - 1, -}; - -enum { - ROCKER_TLV_TX_FRAG_ATTR_UNSPEC, - ROCKER_TLV_TX_FRAG_ATTR_ADDR, /* u64 */ - ROCKER_TLV_TX_FRAG_ATTR_LEN, /* u16 */ - - __ROCKER_TLV_TX_FRAG_ATTR_MAX, - ROCKER_TLV_TX_FRAG_ATTR_MAX = __ROCKER_TLV_TX_FRAG_ATTR_MAX - 1, -}; - -/* - * cmd info nested for OF-DPA msgs - */ - -enum { - ROCKER_TLV_OF_DPA_UNSPEC, - ROCKER_TLV_OF_DPA_TABLE_ID, /* u16 */ - ROCKER_TLV_OF_DPA_PRIORITY, /* u32 */ - ROCKER_TLV_OF_DPA_HARDTIME, /* u32 */ - ROCKER_TLV_OF_DPA_IDLETIME, /* u32 */ - ROCKER_TLV_OF_DPA_COOKIE, /* u64 */ - ROCKER_TLV_OF_DPA_IN_PPORT, /* u32 */ - ROCKER_TLV_OF_DPA_IN_PPORT_MASK, /* u32 */ - ROCKER_TLV_OF_DPA_OUT_PPORT, /* u32 */ - ROCKER_TLV_OF_DPA_GOTO_TABLE_ID, /* u16 */ - ROCKER_TLV_OF_DPA_GROUP_ID, /* u32 */ - ROCKER_TLV_OF_DPA_GROUP_ID_LOWER, /* u32 */ - ROCKER_TLV_OF_DPA_GROUP_COUNT, /* u16 */ - ROCKER_TLV_OF_DPA_GROUP_IDS, /* u32 array */ - ROCKER_TLV_OF_DPA_VLAN_ID, /* __be16 */ - ROCKER_TLV_OF_DPA_VLAN_ID_MASK, /* __be16 */ - ROCKER_TLV_OF_DPA_VLAN_PCP, /* __be16 */ - ROCKER_TLV_OF_DPA_VLAN_PCP_MASK, /* __be16 */ - ROCKER_TLV_OF_DPA_VLAN_PCP_ACTION, /* u8 */ - ROCKER_TLV_OF_DPA_NEW_VLAN_ID, /* __be16 */ - ROCKER_TLV_OF_DPA_NEW_VLAN_PCP, /* u8 */ - ROCKER_TLV_OF_DPA_TUNNEL_ID, /* u32 */ - ROCKER_TLV_OF_DPA_TUNNEL_LPORT, /* u32 */ - ROCKER_TLV_OF_DPA_ETHERTYPE, /* __be16 */ - ROCKER_TLV_OF_DPA_DST_MAC, /* binary */ - ROCKER_TLV_OF_DPA_DST_MAC_MASK, /* binary */ - ROCKER_TLV_OF_DPA_SRC_MAC, /* binary */ - ROCKER_TLV_OF_DPA_SRC_MAC_MASK, /* binary */ - ROCKER_TLV_OF_DPA_IP_PROTO, /* u8 */ - ROCKER_TLV_OF_DPA_IP_PROTO_MASK, /* u8 */ - ROCKER_TLV_OF_DPA_IP_DSCP, /* u8 */ - ROCKER_TLV_OF_DPA_IP_DSCP_MASK, /* u8 */ - ROCKER_TLV_OF_DPA_IP_DSCP_ACTION, /* u8 */ - ROCKER_TLV_OF_DPA_NEW_IP_DSCP, /* u8 */ - ROCKER_TLV_OF_DPA_IP_ECN, /* u8 */ - ROCKER_TLV_OF_DPA_IP_ECN_MASK, /* u8 */ - ROCKER_TLV_OF_DPA_DST_IP, /* __be32 */ - ROCKER_TLV_OF_DPA_DST_IP_MASK, /* __be32 */ - ROCKER_TLV_OF_DPA_SRC_IP, /* __be32 */ - ROCKER_TLV_OF_DPA_SRC_IP_MASK, /* __be32 */ - ROCKER_TLV_OF_DPA_DST_IPV6, /* binary */ - ROCKER_TLV_OF_DPA_DST_IPV6_MASK, /* binary */ - ROCKER_TLV_OF_DPA_SRC_IPV6, /* binary */ - ROCKER_TLV_OF_DPA_SRC_IPV6_MASK, /* binary */ - ROCKER_TLV_OF_DPA_SRC_ARP_IP, /* __be32 */ - ROCKER_TLV_OF_DPA_SRC_ARP_IP_MASK, /* __be32 */ - ROCKER_TLV_OF_DPA_L4_DST_PORT, /* __be16 */ - ROCKER_TLV_OF_DPA_L4_DST_PORT_MASK, /* __be16 */ - ROCKER_TLV_OF_DPA_L4_SRC_PORT, /* __be16 */ - ROCKER_TLV_OF_DPA_L4_SRC_PORT_MASK, /* __be16 */ - ROCKER_TLV_OF_DPA_ICMP_TYPE, /* u8 */ - ROCKER_TLV_OF_DPA_ICMP_TYPE_MASK, /* u8 */ - ROCKER_TLV_OF_DPA_ICMP_CODE, /* u8 */ - ROCKER_TLV_OF_DPA_ICMP_CODE_MASK, /* u8 */ - ROCKER_TLV_OF_DPA_IPV6_LABEL, /* __be32 */ - ROCKER_TLV_OF_DPA_IPV6_LABEL_MASK, /* __be32 */ - ROCKER_TLV_OF_DPA_QUEUE_ID_ACTION, /* u8 */ - ROCKER_TLV_OF_DPA_NEW_QUEUE_ID, /* u8 */ - ROCKER_TLV_OF_DPA_CLEAR_ACTIONS, /* u32 */ - ROCKER_TLV_OF_DPA_POP_VLAN, /* u8 */ - ROCKER_TLV_OF_DPA_TTL_CHECK, /* u8 */ - ROCKER_TLV_OF_DPA_COPY_CPU_ACTION, /* u8 */ - - __ROCKER_TLV_OF_DPA_MAX, - ROCKER_TLV_OF_DPA_MAX = __ROCKER_TLV_OF_DPA_MAX - 1, -}; - -/* - * OF-DPA table IDs - */ - -enum rocker_of_dpa_table_id { - ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT = 0, - ROCKER_OF_DPA_TABLE_ID_VLAN = 10, - ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC = 20, - ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING = 30, - ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING = 40, - ROCKER_OF_DPA_TABLE_ID_BRIDGING = 50, - ROCKER_OF_DPA_TABLE_ID_ACL_POLICY = 60, -}; - -/* - * OF-DPA flow stats - */ - -enum { - ROCKER_TLV_OF_DPA_FLOW_STAT_UNSPEC, - ROCKER_TLV_OF_DPA_FLOW_STAT_DURATION, /* u32 */ - ROCKER_TLV_OF_DPA_FLOW_STAT_RX_PKTS, /* u64 */ - ROCKER_TLV_OF_DPA_FLOW_STAT_TX_PKTS, /* u64 */ - - __ROCKER_TLV_OF_DPA_FLOW_STAT_MAX, - ROCKER_TLV_OF_DPA_FLOW_STAT_MAX = __ROCKER_TLV_OF_DPA_FLOW_STAT_MAX - 1, -}; - -/* - * OF-DPA group types - */ - -enum rocker_of_dpa_group_type { - ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE = 0, - ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE, - ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST, - ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST, - ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD, - ROCKER_OF_DPA_GROUP_TYPE_L3_INTERFACE, - ROCKER_OF_DPA_GROUP_TYPE_L3_MCAST, - ROCKER_OF_DPA_GROUP_TYPE_L3_ECMP, - ROCKER_OF_DPA_GROUP_TYPE_L2_OVERLAY, -}; - -/* - * OF-DPA group L2 overlay types - */ - -enum rocker_of_dpa_overlay_type { - ROCKER_OF_DPA_OVERLAY_TYPE_FLOOD_UCAST = 0, - ROCKER_OF_DPA_OVERLAY_TYPE_FLOOD_MCAST, - ROCKER_OF_DPA_OVERLAY_TYPE_MCAST_UCAST, - ROCKER_OF_DPA_OVERLAY_TYPE_MCAST_MCAST, -}; - -/* - * OF-DPA group ID encoding - */ - -#define ROCKER_GROUP_TYPE_SHIFT 28 -#define ROCKER_GROUP_TYPE_MASK 0xf0000000 -#define ROCKER_GROUP_VLAN_ID_SHIFT 16 -#define ROCKER_GROUP_VLAN_ID_MASK 0x0fff0000 -#define ROCKER_GROUP_PORT_SHIFT 0 -#define ROCKER_GROUP_PORT_MASK 0x0000ffff -#define ROCKER_GROUP_TUNNEL_ID_SHIFT 12 -#define ROCKER_GROUP_TUNNEL_ID_MASK 0x0ffff000 -#define ROCKER_GROUP_SUBTYPE_SHIFT 10 -#define ROCKER_GROUP_SUBTYPE_MASK 0x00000c00 -#define ROCKER_GROUP_INDEX_SHIFT 0 -#define ROCKER_GROUP_INDEX_MASK 0x0000ffff -#define ROCKER_GROUP_INDEX_LONG_SHIFT 0 -#define ROCKER_GROUP_INDEX_LONG_MASK 0x0fffffff - -#define ROCKER_GROUP_TYPE_GET(group_id) \ - (((group_id) & ROCKER_GROUP_TYPE_MASK) >> ROCKER_GROUP_TYPE_SHIFT) -#define ROCKER_GROUP_TYPE_SET(type) \ - (((type) << ROCKER_GROUP_TYPE_SHIFT) & ROCKER_GROUP_TYPE_MASK) -#define ROCKER_GROUP_VLAN_GET(group_id) \ - (((group_id) & ROCKER_GROUP_VLAN_ID_MASK) >> ROCKER_GROUP_VLAN_ID_SHIFT) -#define ROCKER_GROUP_VLAN_SET(vlan_id) \ - (((vlan_id) << ROCKER_GROUP_VLAN_ID_SHIFT) & ROCKER_GROUP_VLAN_ID_MASK) -#define ROCKER_GROUP_PORT_GET(group_id) \ - (((group_id) & ROCKER_GROUP_PORT_MASK) >> ROCKER_GROUP_PORT_SHIFT) -#define ROCKER_GROUP_PORT_SET(port) \ - (((port) << ROCKER_GROUP_PORT_SHIFT) & ROCKER_GROUP_PORT_MASK) -#define ROCKER_GROUP_INDEX_GET(group_id) \ - (((group_id) & ROCKER_GROUP_INDEX_MASK) >> ROCKER_GROUP_INDEX_SHIFT) -#define ROCKER_GROUP_INDEX_SET(index) \ - (((index) << ROCKER_GROUP_INDEX_SHIFT) & ROCKER_GROUP_INDEX_MASK) -#define ROCKER_GROUP_INDEX_LONG_GET(group_id) \ - (((group_id) & ROCKER_GROUP_INDEX_LONG_MASK) >> \ - ROCKER_GROUP_INDEX_LONG_SHIFT) -#define ROCKER_GROUP_INDEX_LONG_SET(index) \ - (((index) << ROCKER_GROUP_INDEX_LONG_SHIFT) & \ - ROCKER_GROUP_INDEX_LONG_MASK) - -#define ROCKER_GROUP_NONE 0 -#define ROCKER_GROUP_L2_INTERFACE(vlan_id, port) \ - (ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE) |\ - ROCKER_GROUP_VLAN_SET(ntohs(vlan_id)) | ROCKER_GROUP_PORT_SET(port)) -#define ROCKER_GROUP_L2_REWRITE(index) \ - (ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE) |\ - ROCKER_GROUP_INDEX_LONG_SET(index)) -#define ROCKER_GROUP_L2_MCAST(vlan_id, index) \ - (ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST) |\ - ROCKER_GROUP_VLAN_SET(ntohs(vlan_id)) | ROCKER_GROUP_INDEX_SET(index)) -#define ROCKER_GROUP_L2_FLOOD(vlan_id, index) \ - (ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD) |\ - ROCKER_GROUP_VLAN_SET(ntohs(vlan_id)) | ROCKER_GROUP_INDEX_SET(index)) -#define ROCKER_GROUP_L3_UNICAST(index) \ - (ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST) |\ - ROCKER_GROUP_INDEX_LONG_SET(index)) - -/* - * Rocker general purpose registers - */ -#define ROCKER_CONTROL 0x0300 -#define ROCKER_PORT_PHYS_COUNT 0x0304 -#define ROCKER_PORT_PHYS_LINK_STATUS 0x0310 /* 8-byte */ -#define ROCKER_PORT_PHYS_ENABLE 0x0318 /* 8-byte */ -#define ROCKER_SWITCH_ID 0x0320 /* 8-byte */ - -/* - * Rocker control bits - */ -#define ROCKER_CONTROL_RESET (1 << 0) - -#endif /* _ROCKER_HW_ */ diff --git a/qemu/hw/net/rocker/rocker_of_dpa.c b/qemu/hw/net/rocker/rocker_of_dpa.c deleted file mode 100644 index 0a134ebca..000000000 --- a/qemu/hw/net/rocker/rocker_of_dpa.c +++ /dev/null @@ -1,2627 +0,0 @@ -/* - * QEMU rocker switch emulation - OF-DPA flow processing support - * - * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "qemu/osdep.h" -#include "net/eth.h" -#include "qemu/iov.h" -#include "qemu/timer.h" -#include "qmp-commands.h" - -#include "rocker.h" -#include "rocker_hw.h" -#include "rocker_fp.h" -#include "rocker_tlv.h" -#include "rocker_world.h" -#include "rocker_desc.h" -#include "rocker_of_dpa.h" - -static const MACAddr zero_mac = { .a = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; -static const MACAddr ff_mac = { .a = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } }; - -typedef struct of_dpa { - World *world; - GHashTable *flow_tbl; - GHashTable *group_tbl; - unsigned int flow_tbl_max_size; - unsigned int group_tbl_max_size; -} OfDpa; - -/* flow_key stolen mostly from OVS - * - * Note: fields that compare with network packet header fields - * are stored in network order (BE) to avoid per-packet field - * byte-swaps. - */ - -typedef struct of_dpa_flow_key { - uint32_t in_pport; /* ingress port */ - uint32_t tunnel_id; /* overlay tunnel id */ - uint32_t tbl_id; /* table id */ - struct { - __be16 vlan_id; /* 0 if no VLAN */ - MACAddr src; /* ethernet source address */ - MACAddr dst; /* ethernet destination address */ - __be16 type; /* ethernet frame type */ - } eth; - struct { - uint8_t proto; /* IP protocol or ARP opcode */ - uint8_t tos; /* IP ToS */ - uint8_t ttl; /* IP TTL/hop limit */ - uint8_t frag; /* one of FRAG_TYPE_* */ - } ip; - union { - struct { - struct { - __be32 src; /* IP source address */ - __be32 dst; /* IP destination address */ - } addr; - union { - struct { - __be16 src; /* TCP/UDP/SCTP source port */ - __be16 dst; /* TCP/UDP/SCTP destination port */ - __be16 flags; /* TCP flags */ - } tp; - struct { - MACAddr sha; /* ARP source hardware address */ - MACAddr tha; /* ARP target hardware address */ - } arp; - }; - } ipv4; - struct { - struct { - Ipv6Addr src; /* IPv6 source address */ - Ipv6Addr dst; /* IPv6 destination address */ - } addr; - __be32 label; /* IPv6 flow label */ - struct { - __be16 src; /* TCP/UDP/SCTP source port */ - __be16 dst; /* TCP/UDP/SCTP destination port */ - __be16 flags; /* TCP flags */ - } tp; - struct { - Ipv6Addr target; /* ND target address */ - MACAddr sll; /* ND source link layer address */ - MACAddr tll; /* ND target link layer address */ - } nd; - } ipv6; - }; - int width; /* how many uint64_t's in key? */ -} OfDpaFlowKey; - -/* Width of key which includes field 'f' in u64s, rounded up */ -#define FLOW_KEY_WIDTH(f) \ - ((offsetof(OfDpaFlowKey, f) + \ - sizeof(((OfDpaFlowKey *)0)->f) + \ - sizeof(uint64_t) - 1) / sizeof(uint64_t)) - -typedef struct of_dpa_flow_action { - uint32_t goto_tbl; - struct { - uint32_t group_id; - uint32_t tun_log_lport; - __be16 vlan_id; - } write; - struct { - __be16 new_vlan_id; - uint32_t out_pport; - uint8_t copy_to_cpu; - __be16 vlan_id; - } apply; -} OfDpaFlowAction; - -typedef struct of_dpa_flow { - uint32_t lpm; - uint32_t priority; - uint32_t hardtime; - uint32_t idletime; - uint64_t cookie; - OfDpaFlowKey key; - OfDpaFlowKey mask; - OfDpaFlowAction action; - struct { - uint64_t hits; - int64_t install_time; - int64_t refresh_time; - uint64_t rx_pkts; - uint64_t tx_pkts; - } stats; -} OfDpaFlow; - -typedef struct of_dpa_flow_pkt_fields { - uint32_t tunnel_id; - struct eth_header *ethhdr; - __be16 *h_proto; - struct vlan_header *vlanhdr; - struct ip_header *ipv4hdr; - struct ip6_header *ipv6hdr; - Ipv6Addr *ipv6_src_addr; - Ipv6Addr *ipv6_dst_addr; -} OfDpaFlowPktFields; - -typedef struct of_dpa_flow_context { - uint32_t in_pport; - uint32_t tunnel_id; - struct iovec *iov; - int iovcnt; - struct eth_header ethhdr_rewrite; - struct vlan_header vlanhdr_rewrite; - struct vlan_header vlanhdr; - OfDpa *of_dpa; - OfDpaFlowPktFields fields; - OfDpaFlowAction action_set; -} OfDpaFlowContext; - -typedef struct of_dpa_flow_match { - OfDpaFlowKey value; - OfDpaFlow *best; -} OfDpaFlowMatch; - -typedef struct of_dpa_group { - uint32_t id; - union { - struct { - uint32_t out_pport; - uint8_t pop_vlan; - } l2_interface; - struct { - uint32_t group_id; - MACAddr src_mac; - MACAddr dst_mac; - __be16 vlan_id; - } l2_rewrite; - struct { - uint16_t group_count; - uint32_t *group_ids; - } l2_flood; - struct { - uint32_t group_id; - MACAddr src_mac; - MACAddr dst_mac; - __be16 vlan_id; - uint8_t ttl_check; - } l3_unicast; - }; -} OfDpaGroup; - -static int of_dpa_mask2prefix(__be32 mask) -{ - int i; - int count = 32; - - for (i = 0; i < 32; i++) { - if (!(ntohl(mask) & ((2 << i) - 1))) { - count--; - } - } - - return count; -} - -#if defined(DEBUG_ROCKER) -static void of_dpa_flow_key_dump(OfDpaFlowKey *key, OfDpaFlowKey *mask) -{ - char buf[512], *b = buf, *mac; - - b += sprintf(b, " tbl %2d", key->tbl_id); - - if (key->in_pport || (mask && mask->in_pport)) { - b += sprintf(b, " in_pport %2d", key->in_pport); - if (mask && mask->in_pport != 0xffffffff) { - b += sprintf(b, "/0x%08x", key->in_pport); - } - } - - if (key->tunnel_id || (mask && mask->tunnel_id)) { - b += sprintf(b, " tun %8d", key->tunnel_id); - if (mask && mask->tunnel_id != 0xffffffff) { - b += sprintf(b, "/0x%08x", key->tunnel_id); - } - } - - if (key->eth.vlan_id || (mask && mask->eth.vlan_id)) { - b += sprintf(b, " vlan %4d", ntohs(key->eth.vlan_id)); - if (mask && mask->eth.vlan_id != 0xffff) { - b += sprintf(b, "/0x%04x", ntohs(key->eth.vlan_id)); - } - } - - if (memcmp(key->eth.src.a, zero_mac.a, ETH_ALEN) || - (mask && memcmp(mask->eth.src.a, zero_mac.a, ETH_ALEN))) { - mac = qemu_mac_strdup_printf(key->eth.src.a); - b += sprintf(b, " src %s", mac); - g_free(mac); - if (mask && memcmp(mask->eth.src.a, ff_mac.a, ETH_ALEN)) { - mac = qemu_mac_strdup_printf(mask->eth.src.a); - b += sprintf(b, "/%s", mac); - g_free(mac); - } - } - - if (memcmp(key->eth.dst.a, zero_mac.a, ETH_ALEN) || - (mask && memcmp(mask->eth.dst.a, zero_mac.a, ETH_ALEN))) { - mac = qemu_mac_strdup_printf(key->eth.dst.a); - b += sprintf(b, " dst %s", mac); - g_free(mac); - if (mask && memcmp(mask->eth.dst.a, ff_mac.a, ETH_ALEN)) { - mac = qemu_mac_strdup_printf(mask->eth.dst.a); - b += sprintf(b, "/%s", mac); - g_free(mac); - } - } - - if (key->eth.type || (mask && mask->eth.type)) { - b += sprintf(b, " type 0x%04x", ntohs(key->eth.type)); - if (mask && mask->eth.type != 0xffff) { - b += sprintf(b, "/0x%04x", ntohs(mask->eth.type)); - } - switch (ntohs(key->eth.type)) { - case 0x0800: - case 0x86dd: - if (key->ip.proto || (mask && mask->ip.proto)) { - b += sprintf(b, " ip proto %2d", key->ip.proto); - if (mask && mask->ip.proto != 0xff) { - b += sprintf(b, "/0x%02x", mask->ip.proto); - } - } - if (key->ip.tos || (mask && mask->ip.tos)) { - b += sprintf(b, " ip tos %2d", key->ip.tos); - if (mask && mask->ip.tos != 0xff) { - b += sprintf(b, "/0x%02x", mask->ip.tos); - } - } - break; - } - switch (ntohs(key->eth.type)) { - case 0x0800: - if (key->ipv4.addr.dst || (mask && mask->ipv4.addr.dst)) { - b += sprintf(b, " dst %s", - inet_ntoa(*(struct in_addr *)&key->ipv4.addr.dst)); - if (mask) { - b += sprintf(b, "/%d", - of_dpa_mask2prefix(mask->ipv4.addr.dst)); - } - } - break; - } - } - - DPRINTF("%s\n", buf); -} -#else -#define of_dpa_flow_key_dump(k, m) -#endif - -static void _of_dpa_flow_match(void *key, void *value, void *user_data) -{ - OfDpaFlow *flow = value; - OfDpaFlowMatch *match = user_data; - uint64_t *k = (uint64_t *)&flow->key; - uint64_t *m = (uint64_t *)&flow->mask; - uint64_t *v = (uint64_t *)&match->value; - int i; - - if (flow->key.tbl_id == match->value.tbl_id) { - of_dpa_flow_key_dump(&flow->key, &flow->mask); - } - - if (flow->key.width > match->value.width) { - return; - } - - for (i = 0; i < flow->key.width; i++, k++, m++, v++) { - if ((~*k & *m & *v) | (*k & *m & ~*v)) { - return; - } - } - - DPRINTF("match\n"); - - if (!match->best || - flow->priority > match->best->priority || - flow->lpm > match->best->lpm) { - match->best = flow; - } -} - -static OfDpaFlow *of_dpa_flow_match(OfDpa *of_dpa, OfDpaFlowMatch *match) -{ - DPRINTF("\nnew search\n"); - of_dpa_flow_key_dump(&match->value, NULL); - - g_hash_table_foreach(of_dpa->flow_tbl, _of_dpa_flow_match, match); - - return match->best; -} - -static OfDpaFlow *of_dpa_flow_find(OfDpa *of_dpa, uint64_t cookie) -{ - return g_hash_table_lookup(of_dpa->flow_tbl, &cookie); -} - -static int of_dpa_flow_add(OfDpa *of_dpa, OfDpaFlow *flow) -{ - g_hash_table_insert(of_dpa->flow_tbl, &flow->cookie, flow); - - return ROCKER_OK; -} - -static void of_dpa_flow_del(OfDpa *of_dpa, OfDpaFlow *flow) -{ - g_hash_table_remove(of_dpa->flow_tbl, &flow->cookie); -} - -static OfDpaFlow *of_dpa_flow_alloc(uint64_t cookie) -{ - OfDpaFlow *flow; - int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) / 1000; - - flow = g_new0(OfDpaFlow, 1); - if (!flow) { - return NULL; - } - - flow->cookie = cookie; - flow->mask.tbl_id = 0xffffffff; - - flow->stats.install_time = flow->stats.refresh_time = now; - - return flow; -} - -static void of_dpa_flow_pkt_hdr_reset(OfDpaFlowContext *fc) -{ - OfDpaFlowPktFields *fields = &fc->fields; - - fc->iov[0].iov_base = fields->ethhdr; - fc->iov[0].iov_len = sizeof(struct eth_header); - fc->iov[1].iov_base = fields->vlanhdr; - fc->iov[1].iov_len = fields->vlanhdr ? sizeof(struct vlan_header) : 0; -} - -static void of_dpa_flow_pkt_parse(OfDpaFlowContext *fc, - const struct iovec *iov, int iovcnt) -{ - OfDpaFlowPktFields *fields = &fc->fields; - size_t sofar = 0; - int i; - - sofar += sizeof(struct eth_header); - if (iov->iov_len < sofar) { - DPRINTF("flow_pkt_parse underrun on eth_header\n"); - return; - } - - fields->ethhdr = iov->iov_base; - fields->h_proto = &fields->ethhdr->h_proto; - - if (ntohs(*fields->h_proto) == ETH_P_VLAN) { - sofar += sizeof(struct vlan_header); - if (iov->iov_len < sofar) { - DPRINTF("flow_pkt_parse underrun on vlan_header\n"); - return; - } - fields->vlanhdr = (struct vlan_header *)(fields->ethhdr + 1); - fields->h_proto = &fields->vlanhdr->h_proto; - } - - switch (ntohs(*fields->h_proto)) { - case ETH_P_IP: - sofar += sizeof(struct ip_header); - if (iov->iov_len < sofar) { - DPRINTF("flow_pkt_parse underrun on ip_header\n"); - return; - } - fields->ipv4hdr = (struct ip_header *)(fields->h_proto + 1); - break; - case ETH_P_IPV6: - sofar += sizeof(struct ip6_header); - if (iov->iov_len < sofar) { - DPRINTF("flow_pkt_parse underrun on ip6_header\n"); - return; - } - fields->ipv6hdr = (struct ip6_header *)(fields->h_proto + 1); - break; - } - - /* To facilitate (potential) VLAN tag insertion, Make a - * copy of the iov and insert two new vectors at the - * beginning for eth hdr and vlan hdr. No data is copied, - * just the vectors. - */ - - of_dpa_flow_pkt_hdr_reset(fc); - - fc->iov[2].iov_base = fields->h_proto + 1; - fc->iov[2].iov_len = iov->iov_len - fc->iov[0].iov_len - fc->iov[1].iov_len; - - for (i = 1; i < iovcnt; i++) { - fc->iov[i+2] = iov[i]; - } - - fc->iovcnt = iovcnt + 2; -} - -static void of_dpa_flow_pkt_insert_vlan(OfDpaFlowContext *fc, __be16 vlan_id) -{ - OfDpaFlowPktFields *fields = &fc->fields; - uint16_t h_proto = fields->ethhdr->h_proto; - - if (fields->vlanhdr) { - DPRINTF("flow_pkt_insert_vlan packet already has vlan\n"); - return; - } - - fields->ethhdr->h_proto = htons(ETH_P_VLAN); - fields->vlanhdr = &fc->vlanhdr; - fields->vlanhdr->h_tci = vlan_id; - fields->vlanhdr->h_proto = h_proto; - fields->h_proto = &fields->vlanhdr->h_proto; - - fc->iov[1].iov_base = fields->vlanhdr; - fc->iov[1].iov_len = sizeof(struct vlan_header); -} - -static void of_dpa_flow_pkt_strip_vlan(OfDpaFlowContext *fc) -{ - OfDpaFlowPktFields *fields = &fc->fields; - - if (!fields->vlanhdr) { - return; - } - - fc->iov[0].iov_len -= sizeof(fields->ethhdr->h_proto); - fc->iov[1].iov_base = fields->h_proto; - fc->iov[1].iov_len = sizeof(fields->ethhdr->h_proto); -} - -static void of_dpa_flow_pkt_hdr_rewrite(OfDpaFlowContext *fc, - uint8_t *src_mac, uint8_t *dst_mac, - __be16 vlan_id) -{ - OfDpaFlowPktFields *fields = &fc->fields; - - if (src_mac || dst_mac) { - memcpy(&fc->ethhdr_rewrite, fields->ethhdr, sizeof(struct eth_header)); - if (src_mac && memcmp(src_mac, zero_mac.a, ETH_ALEN)) { - memcpy(fc->ethhdr_rewrite.h_source, src_mac, ETH_ALEN); - } - if (dst_mac && memcmp(dst_mac, zero_mac.a, ETH_ALEN)) { - memcpy(fc->ethhdr_rewrite.h_dest, dst_mac, ETH_ALEN); - } - fc->iov[0].iov_base = &fc->ethhdr_rewrite; - } - - if (vlan_id && fields->vlanhdr) { - fc->vlanhdr_rewrite = fc->vlanhdr; - fc->vlanhdr_rewrite.h_tci = vlan_id; - fc->iov[1].iov_base = &fc->vlanhdr_rewrite; - } -} - -static void of_dpa_flow_ig_tbl(OfDpaFlowContext *fc, uint32_t tbl_id); - -static void of_dpa_ig_port_build_match(OfDpaFlowContext *fc, - OfDpaFlowMatch *match) -{ - match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT; - match->value.in_pport = fc->in_pport; - match->value.width = FLOW_KEY_WIDTH(tbl_id); -} - -static void of_dpa_ig_port_miss(OfDpaFlowContext *fc) -{ - uint32_t port; - - /* The default on miss is for packets from physical ports - * to go to the VLAN Flow Table. There is no default rule - * for packets from logical ports, which are dropped on miss. - */ - - if (fp_port_from_pport(fc->in_pport, &port)) { - of_dpa_flow_ig_tbl(fc, ROCKER_OF_DPA_TABLE_ID_VLAN); - } -} - -static void of_dpa_vlan_build_match(OfDpaFlowContext *fc, - OfDpaFlowMatch *match) -{ - match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_VLAN; - match->value.in_pport = fc->in_pport; - if (fc->fields.vlanhdr) { - match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci; - } - match->value.width = FLOW_KEY_WIDTH(eth.vlan_id); -} - -static void of_dpa_vlan_insert(OfDpaFlowContext *fc, - OfDpaFlow *flow) -{ - if (flow->action.apply.new_vlan_id) { - of_dpa_flow_pkt_insert_vlan(fc, flow->action.apply.new_vlan_id); - } -} - -static void of_dpa_term_mac_build_match(OfDpaFlowContext *fc, - OfDpaFlowMatch *match) -{ - match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC; - match->value.in_pport = fc->in_pport; - match->value.eth.type = *fc->fields.h_proto; - match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci; - memcpy(match->value.eth.dst.a, fc->fields.ethhdr->h_dest, - sizeof(match->value.eth.dst.a)); - match->value.width = FLOW_KEY_WIDTH(eth.type); -} - -static void of_dpa_term_mac_miss(OfDpaFlowContext *fc) -{ - of_dpa_flow_ig_tbl(fc, ROCKER_OF_DPA_TABLE_ID_BRIDGING); -} - -static void of_dpa_apply_actions(OfDpaFlowContext *fc, - OfDpaFlow *flow) -{ - fc->action_set.apply.copy_to_cpu = flow->action.apply.copy_to_cpu; - fc->action_set.apply.vlan_id = flow->key.eth.vlan_id; -} - -static void of_dpa_bridging_build_match(OfDpaFlowContext *fc, - OfDpaFlowMatch *match) -{ - match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_BRIDGING; - if (fc->fields.vlanhdr) { - match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci; - } else if (fc->tunnel_id) { - match->value.tunnel_id = fc->tunnel_id; - } - memcpy(match->value.eth.dst.a, fc->fields.ethhdr->h_dest, - sizeof(match->value.eth.dst.a)); - match->value.width = FLOW_KEY_WIDTH(eth.dst); -} - -static void of_dpa_bridging_learn(OfDpaFlowContext *fc, - OfDpaFlow *dst_flow) -{ - OfDpaFlowMatch match = { { 0, }, }; - OfDpaFlow *flow; - uint8_t *addr; - uint16_t vlan_id; - int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) / 1000; - int64_t refresh_delay = 1; - - /* Do a lookup in bridge table by src_mac/vlan */ - - addr = fc->fields.ethhdr->h_source; - vlan_id = fc->fields.vlanhdr->h_tci; - - match.value.tbl_id = ROCKER_OF_DPA_TABLE_ID_BRIDGING; - match.value.eth.vlan_id = vlan_id; - memcpy(match.value.eth.dst.a, addr, sizeof(match.value.eth.dst.a)); - match.value.width = FLOW_KEY_WIDTH(eth.dst); - - flow = of_dpa_flow_match(fc->of_dpa, &match); - if (flow) { - if (!memcmp(flow->mask.eth.dst.a, ff_mac.a, - sizeof(flow->mask.eth.dst.a))) { - /* src_mac/vlan already learned; if in_port and out_port - * don't match, the end station has moved and the port - * needs updating */ - /* XXX implement the in_port/out_port check */ - if (now - flow->stats.refresh_time < refresh_delay) { - return; - } - flow->stats.refresh_time = now; - } - } - - /* Let driver know about mac/vlan. This may be a new mac/vlan - * or a refresh of existing mac/vlan that's been hit after the - * refresh_delay. - */ - - rocker_event_mac_vlan_seen(world_rocker(fc->of_dpa->world), - fc->in_pport, addr, vlan_id); -} - -static void of_dpa_bridging_miss(OfDpaFlowContext *fc) -{ - of_dpa_bridging_learn(fc, NULL); - of_dpa_flow_ig_tbl(fc, ROCKER_OF_DPA_TABLE_ID_ACL_POLICY); -} - -static void of_dpa_bridging_action_write(OfDpaFlowContext *fc, - OfDpaFlow *flow) -{ - if (flow->action.write.group_id != ROCKER_GROUP_NONE) { - fc->action_set.write.group_id = flow->action.write.group_id; - } - fc->action_set.write.tun_log_lport = flow->action.write.tun_log_lport; -} - -static void of_dpa_unicast_routing_build_match(OfDpaFlowContext *fc, - OfDpaFlowMatch *match) -{ - match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING; - match->value.eth.type = *fc->fields.h_proto; - if (fc->fields.ipv4hdr) { - match->value.ipv4.addr.dst = fc->fields.ipv4hdr->ip_dst; - } - if (fc->fields.ipv6_dst_addr) { - memcpy(&match->value.ipv6.addr.dst, fc->fields.ipv6_dst_addr, - sizeof(match->value.ipv6.addr.dst)); - } - match->value.width = FLOW_KEY_WIDTH(ipv6.addr.dst); -} - -static void of_dpa_unicast_routing_miss(OfDpaFlowContext *fc) -{ - of_dpa_flow_ig_tbl(fc, ROCKER_OF_DPA_TABLE_ID_ACL_POLICY); -} - -static void of_dpa_unicast_routing_action_write(OfDpaFlowContext *fc, - OfDpaFlow *flow) -{ - if (flow->action.write.group_id != ROCKER_GROUP_NONE) { - fc->action_set.write.group_id = flow->action.write.group_id; - } -} - -static void -of_dpa_multicast_routing_build_match(OfDpaFlowContext *fc, - OfDpaFlowMatch *match) -{ - match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING; - match->value.eth.type = *fc->fields.h_proto; - match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci; - if (fc->fields.ipv4hdr) { - match->value.ipv4.addr.src = fc->fields.ipv4hdr->ip_src; - match->value.ipv4.addr.dst = fc->fields.ipv4hdr->ip_dst; - } - if (fc->fields.ipv6_src_addr) { - memcpy(&match->value.ipv6.addr.src, fc->fields.ipv6_src_addr, - sizeof(match->value.ipv6.addr.src)); - } - if (fc->fields.ipv6_dst_addr) { - memcpy(&match->value.ipv6.addr.dst, fc->fields.ipv6_dst_addr, - sizeof(match->value.ipv6.addr.dst)); - } - match->value.width = FLOW_KEY_WIDTH(ipv6.addr.dst); -} - -static void of_dpa_multicast_routing_miss(OfDpaFlowContext *fc) -{ - of_dpa_flow_ig_tbl(fc, ROCKER_OF_DPA_TABLE_ID_ACL_POLICY); -} - -static void -of_dpa_multicast_routing_action_write(OfDpaFlowContext *fc, - OfDpaFlow *flow) -{ - if (flow->action.write.group_id != ROCKER_GROUP_NONE) { - fc->action_set.write.group_id = flow->action.write.group_id; - } - fc->action_set.write.vlan_id = flow->action.write.vlan_id; -} - -static void of_dpa_acl_build_match(OfDpaFlowContext *fc, - OfDpaFlowMatch *match) -{ - match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_ACL_POLICY; - match->value.in_pport = fc->in_pport; - memcpy(match->value.eth.src.a, fc->fields.ethhdr->h_source, - sizeof(match->value.eth.src.a)); - memcpy(match->value.eth.dst.a, fc->fields.ethhdr->h_dest, - sizeof(match->value.eth.dst.a)); - match->value.eth.type = *fc->fields.h_proto; - match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci; - match->value.width = FLOW_KEY_WIDTH(eth.type); - if (fc->fields.ipv4hdr) { - match->value.ip.proto = fc->fields.ipv4hdr->ip_p; - match->value.ip.tos = fc->fields.ipv4hdr->ip_tos; - match->value.width = FLOW_KEY_WIDTH(ip.tos); - } else if (fc->fields.ipv6hdr) { - match->value.ip.proto = - fc->fields.ipv6hdr->ip6_ctlun.ip6_un1.ip6_un1_nxt; - match->value.ip.tos = 0; /* XXX what goes here? */ - match->value.width = FLOW_KEY_WIDTH(ip.tos); - } -} - -static void of_dpa_eg(OfDpaFlowContext *fc); -static void of_dpa_acl_hit(OfDpaFlowContext *fc, - OfDpaFlow *dst_flow) -{ - of_dpa_eg(fc); -} - -static void of_dpa_acl_action_write(OfDpaFlowContext *fc, - OfDpaFlow *flow) -{ - if (flow->action.write.group_id != ROCKER_GROUP_NONE) { - fc->action_set.write.group_id = flow->action.write.group_id; - } -} - -static void of_dpa_drop(OfDpaFlowContext *fc) -{ - /* drop packet */ -} - -static OfDpaGroup *of_dpa_group_find(OfDpa *of_dpa, - uint32_t group_id) -{ - return g_hash_table_lookup(of_dpa->group_tbl, &group_id); -} - -static int of_dpa_group_add(OfDpa *of_dpa, OfDpaGroup *group) -{ - g_hash_table_insert(of_dpa->group_tbl, &group->id, group); - - return 0; -} - -#if 0 -static int of_dpa_group_mod(OfDpa *of_dpa, OfDpaGroup *group) -{ - OfDpaGroup *old_group = of_dpa_group_find(of_dpa, group->id); - - if (!old_group) { - return -ENOENT; - } - - /* XXX */ - - return 0; -} -#endif - -static int of_dpa_group_del(OfDpa *of_dpa, OfDpaGroup *group) -{ - g_hash_table_remove(of_dpa->group_tbl, &group->id); - - return 0; -} - -#if 0 -static int of_dpa_group_get_stats(OfDpa *of_dpa, uint32_t id) -{ - OfDpaGroup *group = of_dpa_group_find(of_dpa, id); - - if (!group) { - return -ENOENT; - } - - /* XXX get/return stats */ - - return 0; -} -#endif - -static OfDpaGroup *of_dpa_group_alloc(uint32_t id) -{ - OfDpaGroup *group = g_new0(OfDpaGroup, 1); - - if (!group) { - return NULL; - } - - group->id = id; - - return group; -} - -static void of_dpa_output_l2_interface(OfDpaFlowContext *fc, - OfDpaGroup *group) -{ - uint8_t copy_to_cpu = fc->action_set.apply.copy_to_cpu; - - if (group->l2_interface.pop_vlan) { - of_dpa_flow_pkt_strip_vlan(fc); - } - - /* Note: By default, and as per the OpenFlow 1.3.1 - * specification, a packet cannot be forwarded back - * to the IN_PORT from which it came in. An action - * bucket that specifies the particular packet's - * egress port is not evaluated. - */ - - if (group->l2_interface.out_pport == 0) { - rx_produce(fc->of_dpa->world, fc->in_pport, fc->iov, fc->iovcnt, - copy_to_cpu); - } else if (group->l2_interface.out_pport != fc->in_pport) { - rocker_port_eg(world_rocker(fc->of_dpa->world), - group->l2_interface.out_pport, - fc->iov, fc->iovcnt); - } -} - -static void of_dpa_output_l2_rewrite(OfDpaFlowContext *fc, - OfDpaGroup *group) -{ - OfDpaGroup *l2_group = - of_dpa_group_find(fc->of_dpa, group->l2_rewrite.group_id); - - if (!l2_group) { - return; - } - - of_dpa_flow_pkt_hdr_rewrite(fc, group->l2_rewrite.src_mac.a, - group->l2_rewrite.dst_mac.a, - group->l2_rewrite.vlan_id); - of_dpa_output_l2_interface(fc, l2_group); -} - -static void of_dpa_output_l2_flood(OfDpaFlowContext *fc, - OfDpaGroup *group) -{ - OfDpaGroup *l2_group; - int i; - - for (i = 0; i < group->l2_flood.group_count; i++) { - of_dpa_flow_pkt_hdr_reset(fc); - l2_group = of_dpa_group_find(fc->of_dpa, group->l2_flood.group_ids[i]); - if (!l2_group) { - continue; - } - switch (ROCKER_GROUP_TYPE_GET(l2_group->id)) { - case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE: - of_dpa_output_l2_interface(fc, l2_group); - break; - case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE: - of_dpa_output_l2_rewrite(fc, l2_group); - break; - } - } -} - -static void of_dpa_output_l3_unicast(OfDpaFlowContext *fc, OfDpaGroup *group) -{ - OfDpaGroup *l2_group = - of_dpa_group_find(fc->of_dpa, group->l3_unicast.group_id); - - if (!l2_group) { - return; - } - - of_dpa_flow_pkt_hdr_rewrite(fc, group->l3_unicast.src_mac.a, - group->l3_unicast.dst_mac.a, - group->l3_unicast.vlan_id); - /* XXX need ttl_check */ - of_dpa_output_l2_interface(fc, l2_group); -} - -static void of_dpa_eg(OfDpaFlowContext *fc) -{ - OfDpaFlowAction *set = &fc->action_set; - OfDpaGroup *group; - uint32_t group_id; - - /* send a copy of pkt to CPU (controller)? */ - - if (set->apply.copy_to_cpu) { - group_id = ROCKER_GROUP_L2_INTERFACE(set->apply.vlan_id, 0); - group = of_dpa_group_find(fc->of_dpa, group_id); - if (group) { - of_dpa_output_l2_interface(fc, group); - of_dpa_flow_pkt_hdr_reset(fc); - } - } - - /* process group write actions */ - - if (!set->write.group_id) { - return; - } - - group = of_dpa_group_find(fc->of_dpa, set->write.group_id); - if (!group) { - return; - } - - switch (ROCKER_GROUP_TYPE_GET(group->id)) { - case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE: - of_dpa_output_l2_interface(fc, group); - break; - case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE: - of_dpa_output_l2_rewrite(fc, group); - break; - case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD: - case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST: - of_dpa_output_l2_flood(fc, group); - break; - case ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST: - of_dpa_output_l3_unicast(fc, group); - break; - } -} - -typedef struct of_dpa_flow_tbl_ops { - void (*build_match)(OfDpaFlowContext *fc, OfDpaFlowMatch *match); - void (*hit)(OfDpaFlowContext *fc, OfDpaFlow *flow); - void (*miss)(OfDpaFlowContext *fc); - void (*hit_no_goto)(OfDpaFlowContext *fc); - void (*action_apply)(OfDpaFlowContext *fc, OfDpaFlow *flow); - void (*action_write)(OfDpaFlowContext *fc, OfDpaFlow *flow); -} OfDpaFlowTblOps; - -static OfDpaFlowTblOps of_dpa_tbl_ops[] = { - [ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT] = { - .build_match = of_dpa_ig_port_build_match, - .miss = of_dpa_ig_port_miss, - .hit_no_goto = of_dpa_drop, - }, - [ROCKER_OF_DPA_TABLE_ID_VLAN] = { - .build_match = of_dpa_vlan_build_match, - .hit_no_goto = of_dpa_drop, - .action_apply = of_dpa_vlan_insert, - }, - [ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC] = { - .build_match = of_dpa_term_mac_build_match, - .miss = of_dpa_term_mac_miss, - .hit_no_goto = of_dpa_drop, - .action_apply = of_dpa_apply_actions, - }, - [ROCKER_OF_DPA_TABLE_ID_BRIDGING] = { - .build_match = of_dpa_bridging_build_match, - .hit = of_dpa_bridging_learn, - .miss = of_dpa_bridging_miss, - .hit_no_goto = of_dpa_drop, - .action_apply = of_dpa_apply_actions, - .action_write = of_dpa_bridging_action_write, - }, - [ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING] = { - .build_match = of_dpa_unicast_routing_build_match, - .miss = of_dpa_unicast_routing_miss, - .hit_no_goto = of_dpa_drop, - .action_write = of_dpa_unicast_routing_action_write, - }, - [ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING] = { - .build_match = of_dpa_multicast_routing_build_match, - .miss = of_dpa_multicast_routing_miss, - .hit_no_goto = of_dpa_drop, - .action_write = of_dpa_multicast_routing_action_write, - }, - [ROCKER_OF_DPA_TABLE_ID_ACL_POLICY] = { - .build_match = of_dpa_acl_build_match, - .hit = of_dpa_acl_hit, - .miss = of_dpa_eg, - .action_apply = of_dpa_apply_actions, - .action_write = of_dpa_acl_action_write, - }, -}; - -static void of_dpa_flow_ig_tbl(OfDpaFlowContext *fc, uint32_t tbl_id) -{ - OfDpaFlowTblOps *ops = &of_dpa_tbl_ops[tbl_id]; - OfDpaFlowMatch match = { { 0, }, }; - OfDpaFlow *flow; - - if (ops->build_match) { - ops->build_match(fc, &match); - } else { - return; - } - - flow = of_dpa_flow_match(fc->of_dpa, &match); - if (!flow) { - if (ops->miss) { - ops->miss(fc); - } - return; - } - - flow->stats.hits++; - - if (ops->action_apply) { - ops->action_apply(fc, flow); - } - - if (ops->action_write) { - ops->action_write(fc, flow); - } - - if (ops->hit) { - ops->hit(fc, flow); - } - - if (flow->action.goto_tbl) { - of_dpa_flow_ig_tbl(fc, flow->action.goto_tbl); - } else if (ops->hit_no_goto) { - ops->hit_no_goto(fc); - } - - /* drop packet */ -} - -static ssize_t of_dpa_ig(World *world, uint32_t pport, - const struct iovec *iov, int iovcnt) -{ - struct iovec iov_copy[iovcnt + 2]; - OfDpaFlowContext fc = { - .of_dpa = world_private(world), - .in_pport = pport, - .iov = iov_copy, - .iovcnt = iovcnt + 2, - }; - - of_dpa_flow_pkt_parse(&fc, iov, iovcnt); - of_dpa_flow_ig_tbl(&fc, ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT); - - return iov_size(iov, iovcnt); -} - -#define ROCKER_TUNNEL_LPORT 0x00010000 - -static int of_dpa_cmd_add_ig_port(OfDpaFlow *flow, RockerTlv **flow_tlvs) -{ - OfDpaFlowKey *key = &flow->key; - OfDpaFlowKey *mask = &flow->mask; - OfDpaFlowAction *action = &flow->action; - bool overlay_tunnel; - - if (!flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT] || - !flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]) { - return -ROCKER_EINVAL; - } - - key->tbl_id = ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT; - key->width = FLOW_KEY_WIDTH(tbl_id); - - key->in_pport = rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT]); - if (flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT_MASK]) { - mask->in_pport = - rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT_MASK]); - } - - overlay_tunnel = !!(key->in_pport & ROCKER_TUNNEL_LPORT); - - action->goto_tbl = - rocker_tlv_get_le16(flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]); - - if (!overlay_tunnel && action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_VLAN) { - return -ROCKER_EINVAL; - } - - if (overlay_tunnel && action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_BRIDGING) { - return -ROCKER_EINVAL; - } - - return ROCKER_OK; -} - -static int of_dpa_cmd_add_vlan(OfDpaFlow *flow, RockerTlv **flow_tlvs) -{ - OfDpaFlowKey *key = &flow->key; - OfDpaFlowKey *mask = &flow->mask; - OfDpaFlowAction *action = &flow->action; - uint32_t port; - bool untagged; - - if (!flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT] || - !flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]) { - DPRINTF("Must give in_pport and vlan_id to install VLAN tbl entry\n"); - return -ROCKER_EINVAL; - } - - key->tbl_id = ROCKER_OF_DPA_TABLE_ID_VLAN; - key->width = FLOW_KEY_WIDTH(eth.vlan_id); - - key->in_pport = rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT]); - if (!fp_port_from_pport(key->in_pport, &port)) { - DPRINTF("in_pport (%d) not a front-panel port\n", key->in_pport); - return -ROCKER_EINVAL; - } - mask->in_pport = 0xffffffff; - - key->eth.vlan_id = rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]); - - if (flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID_MASK]) { - mask->eth.vlan_id = - rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID_MASK]); - } - - if (key->eth.vlan_id) { - untagged = false; /* filtering */ - } else { - untagged = true; - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]) { - action->goto_tbl = - rocker_tlv_get_le16(flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]); - if (action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC) { - DPRINTF("Goto tbl (%d) must be TERM_MAC\n", action->goto_tbl); - return -ROCKER_EINVAL; - } - } - - if (untagged) { - if (!flow_tlvs[ROCKER_TLV_OF_DPA_NEW_VLAN_ID]) { - DPRINTF("Must specify new vlan_id if untagged\n"); - return -ROCKER_EINVAL; - } - action->apply.new_vlan_id = - rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_NEW_VLAN_ID]); - if (1 > ntohs(action->apply.new_vlan_id) || - ntohs(action->apply.new_vlan_id) > 4095) { - DPRINTF("New vlan_id (%d) must be between 1 and 4095\n", - ntohs(action->apply.new_vlan_id)); - return -ROCKER_EINVAL; - } - } - - return ROCKER_OK; -} - -static int of_dpa_cmd_add_term_mac(OfDpaFlow *flow, RockerTlv **flow_tlvs) -{ - OfDpaFlowKey *key = &flow->key; - OfDpaFlowKey *mask = &flow->mask; - OfDpaFlowAction *action = &flow->action; - const MACAddr ipv4_mcast = { .a = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 } }; - const MACAddr ipv4_mask = { .a = { 0xff, 0xff, 0xff, 0x80, 0x00, 0x00 } }; - const MACAddr ipv6_mcast = { .a = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 } }; - const MACAddr ipv6_mask = { .a = { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } }; - uint32_t port; - bool unicast = false; - bool multicast = false; - - if (!flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT] || - !flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT_MASK] || - !flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE] || - !flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC] || - !flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC_MASK] || - !flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID] || - !flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID_MASK]) { - return -ROCKER_EINVAL; - } - - key->tbl_id = ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC; - key->width = FLOW_KEY_WIDTH(eth.type); - - key->in_pport = rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT]); - if (!fp_port_from_pport(key->in_pport, &port)) { - return -ROCKER_EINVAL; - } - mask->in_pport = - rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT_MASK]); - - key->eth.type = rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE]); - if (key->eth.type != htons(0x0800) && key->eth.type != htons(0x86dd)) { - return -ROCKER_EINVAL; - } - mask->eth.type = htons(0xffff); - - memcpy(key->eth.dst.a, - rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]), - sizeof(key->eth.dst.a)); - memcpy(mask->eth.dst.a, - rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC_MASK]), - sizeof(mask->eth.dst.a)); - - if ((key->eth.dst.a[0] & 0x01) == 0x00) { - unicast = true; - } - - /* only two wildcard rules are acceptable for IPv4 and IPv6 multicast */ - if (memcmp(key->eth.dst.a, ipv4_mcast.a, sizeof(key->eth.dst.a)) == 0 && - memcmp(mask->eth.dst.a, ipv4_mask.a, sizeof(mask->eth.dst.a)) == 0) { - multicast = true; - } - if (memcmp(key->eth.dst.a, ipv6_mcast.a, sizeof(key->eth.dst.a)) == 0 && - memcmp(mask->eth.dst.a, ipv6_mask.a, sizeof(mask->eth.dst.a)) == 0) { - multicast = true; - } - - if (!unicast && !multicast) { - return -ROCKER_EINVAL; - } - - key->eth.vlan_id = rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]); - mask->eth.vlan_id = - rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID_MASK]); - - if (flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]) { - action->goto_tbl = - rocker_tlv_get_le16(flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]); - - if (action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING && - action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING) { - return -ROCKER_EINVAL; - } - - if (unicast && - action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING) { - return -ROCKER_EINVAL; - } - - if (multicast && - action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING) { - return -ROCKER_EINVAL; - } - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_COPY_CPU_ACTION]) { - action->apply.copy_to_cpu = - rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_COPY_CPU_ACTION]); - } - - return ROCKER_OK; -} - -static int of_dpa_cmd_add_bridging(OfDpaFlow *flow, RockerTlv **flow_tlvs) -{ - OfDpaFlowKey *key = &flow->key; - OfDpaFlowKey *mask = &flow->mask; - OfDpaFlowAction *action = &flow->action; - bool unicast = false; - bool dst_mac = false; - bool dst_mac_mask = false; - enum { - BRIDGING_MODE_UNKNOWN, - BRIDGING_MODE_VLAN_UCAST, - BRIDGING_MODE_VLAN_MCAST, - BRIDGING_MODE_VLAN_DFLT, - BRIDGING_MODE_TUNNEL_UCAST, - BRIDGING_MODE_TUNNEL_MCAST, - BRIDGING_MODE_TUNNEL_DFLT, - } mode = BRIDGING_MODE_UNKNOWN; - - key->tbl_id = ROCKER_OF_DPA_TABLE_ID_BRIDGING; - - if (flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]) { - key->eth.vlan_id = - rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]); - mask->eth.vlan_id = 0xffff; - key->width = FLOW_KEY_WIDTH(eth.vlan_id); - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_TUNNEL_ID]) { - key->tunnel_id = - rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_TUNNEL_ID]); - mask->tunnel_id = 0xffffffff; - key->width = FLOW_KEY_WIDTH(tunnel_id); - } - - /* can't do VLAN bridging and tunnel bridging at same time */ - if (key->eth.vlan_id && key->tunnel_id) { - DPRINTF("can't do VLAN bridging and tunnel bridging at same time\n"); - return -ROCKER_EINVAL; - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]) { - memcpy(key->eth.dst.a, - rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]), - sizeof(key->eth.dst.a)); - key->width = FLOW_KEY_WIDTH(eth.dst); - dst_mac = true; - unicast = (key->eth.dst.a[0] & 0x01) == 0x00; - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC_MASK]) { - memcpy(mask->eth.dst.a, - rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC_MASK]), - sizeof(mask->eth.dst.a)); - key->width = FLOW_KEY_WIDTH(eth.dst); - dst_mac_mask = true; - } else if (flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]) { - memcpy(mask->eth.dst.a, ff_mac.a, sizeof(mask->eth.dst.a)); - } - - if (key->eth.vlan_id) { - if (dst_mac && !dst_mac_mask) { - mode = unicast ? BRIDGING_MODE_VLAN_UCAST : - BRIDGING_MODE_VLAN_MCAST; - } else if ((dst_mac && dst_mac_mask) || !dst_mac) { - mode = BRIDGING_MODE_VLAN_DFLT; - } - } else if (key->tunnel_id) { - if (dst_mac && !dst_mac_mask) { - mode = unicast ? BRIDGING_MODE_TUNNEL_UCAST : - BRIDGING_MODE_TUNNEL_MCAST; - } else if ((dst_mac && dst_mac_mask) || !dst_mac) { - mode = BRIDGING_MODE_TUNNEL_DFLT; - } - } - - if (mode == BRIDGING_MODE_UNKNOWN) { - DPRINTF("Unknown bridging mode\n"); - return -ROCKER_EINVAL; - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]) { - action->goto_tbl = - rocker_tlv_get_le16(flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]); - if (action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_ACL_POLICY) { - DPRINTF("Briding goto tbl must be ACL policy\n"); - return -ROCKER_EINVAL; - } - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]) { - action->write.group_id = - rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]); - switch (mode) { - case BRIDGING_MODE_VLAN_UCAST: - if (ROCKER_GROUP_TYPE_GET(action->write.group_id) != - ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE) { - DPRINTF("Bridging mode vlan ucast needs L2 " - "interface group (0x%08x)\n", - action->write.group_id); - return -ROCKER_EINVAL; - } - break; - case BRIDGING_MODE_VLAN_MCAST: - if (ROCKER_GROUP_TYPE_GET(action->write.group_id) != - ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST) { - DPRINTF("Bridging mode vlan mcast needs L2 " - "mcast group (0x%08x)\n", - action->write.group_id); - return -ROCKER_EINVAL; - } - break; - case BRIDGING_MODE_VLAN_DFLT: - if (ROCKER_GROUP_TYPE_GET(action->write.group_id) != - ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD) { - DPRINTF("Bridging mode vlan dflt needs L2 " - "flood group (0x%08x)\n", - action->write.group_id); - return -ROCKER_EINVAL; - } - break; - case BRIDGING_MODE_TUNNEL_MCAST: - if (ROCKER_GROUP_TYPE_GET(action->write.group_id) != - ROCKER_OF_DPA_GROUP_TYPE_L2_OVERLAY) { - DPRINTF("Bridging mode tunnel mcast needs L2 " - "overlay group (0x%08x)\n", - action->write.group_id); - return -ROCKER_EINVAL; - } - break; - case BRIDGING_MODE_TUNNEL_DFLT: - if (ROCKER_GROUP_TYPE_GET(action->write.group_id) != - ROCKER_OF_DPA_GROUP_TYPE_L2_OVERLAY) { - DPRINTF("Bridging mode tunnel dflt needs L2 " - "overlay group (0x%08x)\n", - action->write.group_id); - return -ROCKER_EINVAL; - } - break; - default: - return -ROCKER_EINVAL; - } - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_TUNNEL_LPORT]) { - action->write.tun_log_lport = - rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_TUNNEL_LPORT]); - if (mode != BRIDGING_MODE_TUNNEL_UCAST) { - DPRINTF("Have tunnel logical port but not " - "in bridging tunnel mode\n"); - return -ROCKER_EINVAL; - } - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_COPY_CPU_ACTION]) { - action->apply.copy_to_cpu = - rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_COPY_CPU_ACTION]); - } - - return ROCKER_OK; -} - -static int of_dpa_cmd_add_unicast_routing(OfDpaFlow *flow, - RockerTlv **flow_tlvs) -{ - OfDpaFlowKey *key = &flow->key; - OfDpaFlowKey *mask = &flow->mask; - OfDpaFlowAction *action = &flow->action; - enum { - UNICAST_ROUTING_MODE_UNKNOWN, - UNICAST_ROUTING_MODE_IPV4, - UNICAST_ROUTING_MODE_IPV6, - } mode = UNICAST_ROUTING_MODE_UNKNOWN; - uint8_t type; - - if (!flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE]) { - return -ROCKER_EINVAL; - } - - key->tbl_id = ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING; - key->width = FLOW_KEY_WIDTH(ipv6.addr.dst); - - key->eth.type = rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE]); - switch (ntohs(key->eth.type)) { - case 0x0800: - mode = UNICAST_ROUTING_MODE_IPV4; - break; - case 0x86dd: - mode = UNICAST_ROUTING_MODE_IPV6; - break; - default: - return -ROCKER_EINVAL; - } - mask->eth.type = htons(0xffff); - - switch (mode) { - case UNICAST_ROUTING_MODE_IPV4: - if (!flow_tlvs[ROCKER_TLV_OF_DPA_DST_IP]) { - return -ROCKER_EINVAL; - } - key->ipv4.addr.dst = - rocker_tlv_get_u32(flow_tlvs[ROCKER_TLV_OF_DPA_DST_IP]); - if (ipv4_addr_is_multicast(key->ipv4.addr.dst)) { - return -ROCKER_EINVAL; - } - flow->lpm = of_dpa_mask2prefix(htonl(0xffffffff)); - if (flow_tlvs[ROCKER_TLV_OF_DPA_DST_IP_MASK]) { - mask->ipv4.addr.dst = - rocker_tlv_get_u32(flow_tlvs[ROCKER_TLV_OF_DPA_DST_IP_MASK]); - flow->lpm = of_dpa_mask2prefix(mask->ipv4.addr.dst); - } - break; - case UNICAST_ROUTING_MODE_IPV6: - if (!flow_tlvs[ROCKER_TLV_OF_DPA_DST_IPV6]) { - return -ROCKER_EINVAL; - } - memcpy(&key->ipv6.addr.dst, - rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_IPV6]), - sizeof(key->ipv6.addr.dst)); - if (ipv6_addr_is_multicast(&key->ipv6.addr.dst)) { - return -ROCKER_EINVAL; - } - if (flow_tlvs[ROCKER_TLV_OF_DPA_DST_IPV6_MASK]) { - memcpy(&mask->ipv6.addr.dst, - rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_IPV6_MASK]), - sizeof(mask->ipv6.addr.dst)); - } - break; - default: - return -ROCKER_EINVAL; - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]) { - action->goto_tbl = - rocker_tlv_get_le16(flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]); - if (action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_ACL_POLICY) { - return -ROCKER_EINVAL; - } - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]) { - action->write.group_id = - rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]); - type = ROCKER_GROUP_TYPE_GET(action->write.group_id); - if (type != ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE && - type != ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST && - type != ROCKER_OF_DPA_GROUP_TYPE_L3_ECMP) { - return -ROCKER_EINVAL; - } - } - - return ROCKER_OK; -} - -static int of_dpa_cmd_add_multicast_routing(OfDpaFlow *flow, - RockerTlv **flow_tlvs) -{ - OfDpaFlowKey *key = &flow->key; - OfDpaFlowKey *mask = &flow->mask; - OfDpaFlowAction *action = &flow->action; - enum { - MULTICAST_ROUTING_MODE_UNKNOWN, - MULTICAST_ROUTING_MODE_IPV4, - MULTICAST_ROUTING_MODE_IPV6, - } mode = MULTICAST_ROUTING_MODE_UNKNOWN; - - if (!flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE] || - !flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]) { - return -ROCKER_EINVAL; - } - - key->tbl_id = ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING; - key->width = FLOW_KEY_WIDTH(ipv6.addr.dst); - - key->eth.type = rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE]); - switch (ntohs(key->eth.type)) { - case 0x0800: - mode = MULTICAST_ROUTING_MODE_IPV4; - break; - case 0x86dd: - mode = MULTICAST_ROUTING_MODE_IPV6; - break; - default: - return -ROCKER_EINVAL; - } - - key->eth.vlan_id = rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]); - - switch (mode) { - case MULTICAST_ROUTING_MODE_IPV4: - - if (flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IP]) { - key->ipv4.addr.src = - rocker_tlv_get_u32(flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IP]); - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IP_MASK]) { - mask->ipv4.addr.src = - rocker_tlv_get_u32(flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IP_MASK]); - } - - if (!flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IP]) { - if (mask->ipv4.addr.src != 0) { - return -ROCKER_EINVAL; - } - } - - if (!flow_tlvs[ROCKER_TLV_OF_DPA_DST_IP]) { - return -ROCKER_EINVAL; - } - - key->ipv4.addr.dst = - rocker_tlv_get_u32(flow_tlvs[ROCKER_TLV_OF_DPA_DST_IP]); - if (!ipv4_addr_is_multicast(key->ipv4.addr.dst)) { - return -ROCKER_EINVAL; - } - - break; - - case MULTICAST_ROUTING_MODE_IPV6: - - if (flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IPV6]) { - memcpy(&key->ipv6.addr.src, - rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IPV6]), - sizeof(key->ipv6.addr.src)); - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IPV6_MASK]) { - memcpy(&mask->ipv6.addr.src, - rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IPV6_MASK]), - sizeof(mask->ipv6.addr.src)); - } - - if (!flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IPV6]) { - if (mask->ipv6.addr.src.addr32[0] != 0 && - mask->ipv6.addr.src.addr32[1] != 0 && - mask->ipv6.addr.src.addr32[2] != 0 && - mask->ipv6.addr.src.addr32[3] != 0) { - return -ROCKER_EINVAL; - } - } - - if (!flow_tlvs[ROCKER_TLV_OF_DPA_DST_IPV6]) { - return -ROCKER_EINVAL; - } - - memcpy(&key->ipv6.addr.dst, - rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_IPV6]), - sizeof(key->ipv6.addr.dst)); - if (!ipv6_addr_is_multicast(&key->ipv6.addr.dst)) { - return -ROCKER_EINVAL; - } - - break; - - default: - return -ROCKER_EINVAL; - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]) { - action->goto_tbl = - rocker_tlv_get_le16(flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]); - if (action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_ACL_POLICY) { - return -ROCKER_EINVAL; - } - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]) { - action->write.group_id = - rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]); - if (ROCKER_GROUP_TYPE_GET(action->write.group_id) != - ROCKER_OF_DPA_GROUP_TYPE_L3_MCAST) { - return -ROCKER_EINVAL; - } - action->write.vlan_id = key->eth.vlan_id; - } - - return ROCKER_OK; -} - -static int of_dpa_cmd_add_acl_ip(OfDpaFlowKey *key, OfDpaFlowKey *mask, - RockerTlv **flow_tlvs) -{ - key->width = FLOW_KEY_WIDTH(ip.tos); - - key->ip.proto = 0; - key->ip.tos = 0; - mask->ip.proto = 0; - mask->ip.tos = 0; - - if (flow_tlvs[ROCKER_TLV_OF_DPA_IP_PROTO]) { - key->ip.proto = - rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_IP_PROTO]); - } - if (flow_tlvs[ROCKER_TLV_OF_DPA_IP_PROTO_MASK]) { - mask->ip.proto = - rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_IP_PROTO_MASK]); - } - if (flow_tlvs[ROCKER_TLV_OF_DPA_IP_DSCP]) { - key->ip.tos = - rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_IP_DSCP]); - } - if (flow_tlvs[ROCKER_TLV_OF_DPA_IP_DSCP_MASK]) { - mask->ip.tos = - rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_IP_DSCP_MASK]); - } - if (flow_tlvs[ROCKER_TLV_OF_DPA_IP_ECN]) { - key->ip.tos |= - rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_IP_ECN]) << 6; - } - if (flow_tlvs[ROCKER_TLV_OF_DPA_IP_ECN_MASK]) { - mask->ip.tos |= - rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_IP_ECN_MASK]) << 6; - } - - return ROCKER_OK; -} - -static int of_dpa_cmd_add_acl(OfDpaFlow *flow, RockerTlv **flow_tlvs) -{ - OfDpaFlowKey *key = &flow->key; - OfDpaFlowKey *mask = &flow->mask; - OfDpaFlowAction *action = &flow->action; - enum { - ACL_MODE_UNKNOWN, - ACL_MODE_IPV4_VLAN, - ACL_MODE_IPV6_VLAN, - ACL_MODE_IPV4_TENANT, - ACL_MODE_IPV6_TENANT, - ACL_MODE_NON_IP_VLAN, - ACL_MODE_NON_IP_TENANT, - ACL_MODE_ANY_VLAN, - ACL_MODE_ANY_TENANT, - } mode = ACL_MODE_UNKNOWN; - int err = ROCKER_OK; - - if (!flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT] || - !flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE]) { - return -ROCKER_EINVAL; - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID] && - flow_tlvs[ROCKER_TLV_OF_DPA_TUNNEL_ID]) { - return -ROCKER_EINVAL; - } - - key->tbl_id = ROCKER_OF_DPA_TABLE_ID_ACL_POLICY; - key->width = FLOW_KEY_WIDTH(eth.type); - - key->in_pport = rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT]); - if (flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT_MASK]) { - mask->in_pport = - rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT_MASK]); - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC]) { - memcpy(key->eth.src.a, - rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC]), - sizeof(key->eth.src.a)); - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC_MASK]) { - memcpy(mask->eth.src.a, - rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC_MASK]), - sizeof(mask->eth.src.a)); - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]) { - memcpy(key->eth.dst.a, - rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]), - sizeof(key->eth.dst.a)); - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC_MASK]) { - memcpy(mask->eth.dst.a, - rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC_MASK]), - sizeof(mask->eth.dst.a)); - } - - key->eth.type = rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE]); - if (key->eth.type) { - mask->eth.type = 0xffff; - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]) { - key->eth.vlan_id = - rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]); - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID_MASK]) { - mask->eth.vlan_id = - rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID_MASK]); - } - - switch (ntohs(key->eth.type)) { - case 0x0000: - mode = (key->eth.vlan_id) ? ACL_MODE_ANY_VLAN : ACL_MODE_ANY_TENANT; - break; - case 0x0800: - mode = (key->eth.vlan_id) ? ACL_MODE_IPV4_VLAN : ACL_MODE_IPV4_TENANT; - break; - case 0x86dd: - mode = (key->eth.vlan_id) ? ACL_MODE_IPV6_VLAN : ACL_MODE_IPV6_TENANT; - break; - default: - mode = (key->eth.vlan_id) ? ACL_MODE_NON_IP_VLAN : - ACL_MODE_NON_IP_TENANT; - break; - } - - /* XXX only supporting VLAN modes for now */ - if (mode != ACL_MODE_IPV4_VLAN && - mode != ACL_MODE_IPV6_VLAN && - mode != ACL_MODE_NON_IP_VLAN && - mode != ACL_MODE_ANY_VLAN) { - return -ROCKER_EINVAL; - } - - switch (ntohs(key->eth.type)) { - case 0x0800: - case 0x86dd: - err = of_dpa_cmd_add_acl_ip(key, mask, flow_tlvs); - break; - } - - if (err) { - return err; - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]) { - action->write.group_id = - rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]); - } - - if (flow_tlvs[ROCKER_TLV_OF_DPA_COPY_CPU_ACTION]) { - action->apply.copy_to_cpu = - rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_COPY_CPU_ACTION]); - } - - return ROCKER_OK; -} - -static int of_dpa_cmd_flow_add_mod(OfDpa *of_dpa, OfDpaFlow *flow, - RockerTlv **flow_tlvs) -{ - enum rocker_of_dpa_table_id tbl; - int err = ROCKER_OK; - - if (!flow_tlvs[ROCKER_TLV_OF_DPA_TABLE_ID] || - !flow_tlvs[ROCKER_TLV_OF_DPA_PRIORITY] || - !flow_tlvs[ROCKER_TLV_OF_DPA_HARDTIME]) { - return -ROCKER_EINVAL; - } - - tbl = rocker_tlv_get_le16(flow_tlvs[ROCKER_TLV_OF_DPA_TABLE_ID]); - flow->priority = rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_PRIORITY]); - flow->hardtime = rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_HARDTIME]); - - if (flow_tlvs[ROCKER_TLV_OF_DPA_IDLETIME]) { - if (tbl == ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT || - tbl == ROCKER_OF_DPA_TABLE_ID_VLAN || - tbl == ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC) { - return -ROCKER_EINVAL; - } - flow->idletime = - rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IDLETIME]); - } - - switch (tbl) { - case ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT: - err = of_dpa_cmd_add_ig_port(flow, flow_tlvs); - break; - case ROCKER_OF_DPA_TABLE_ID_VLAN: - err = of_dpa_cmd_add_vlan(flow, flow_tlvs); - break; - case ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC: - err = of_dpa_cmd_add_term_mac(flow, flow_tlvs); - break; - case ROCKER_OF_DPA_TABLE_ID_BRIDGING: - err = of_dpa_cmd_add_bridging(flow, flow_tlvs); - break; - case ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING: - err = of_dpa_cmd_add_unicast_routing(flow, flow_tlvs); - break; - case ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING: - err = of_dpa_cmd_add_multicast_routing(flow, flow_tlvs); - break; - case ROCKER_OF_DPA_TABLE_ID_ACL_POLICY: - err = of_dpa_cmd_add_acl(flow, flow_tlvs); - break; - } - - return err; -} - -static int of_dpa_cmd_flow_add(OfDpa *of_dpa, uint64_t cookie, - RockerTlv **flow_tlvs) -{ - OfDpaFlow *flow = of_dpa_flow_find(of_dpa, cookie); - int err = ROCKER_OK; - - if (flow) { - return -ROCKER_EEXIST; - } - - flow = of_dpa_flow_alloc(cookie); - if (!flow) { - return -ROCKER_ENOMEM; - } - - err = of_dpa_cmd_flow_add_mod(of_dpa, flow, flow_tlvs); - if (err) { - g_free(flow); - return err; - } - - return of_dpa_flow_add(of_dpa, flow); -} - -static int of_dpa_cmd_flow_mod(OfDpa *of_dpa, uint64_t cookie, - RockerTlv **flow_tlvs) -{ - OfDpaFlow *flow = of_dpa_flow_find(of_dpa, cookie); - - if (!flow) { - return -ROCKER_ENOENT; - } - - return of_dpa_cmd_flow_add_mod(of_dpa, flow, flow_tlvs); -} - -static int of_dpa_cmd_flow_del(OfDpa *of_dpa, uint64_t cookie) -{ - OfDpaFlow *flow = of_dpa_flow_find(of_dpa, cookie); - - if (!flow) { - return -ROCKER_ENOENT; - } - - of_dpa_flow_del(of_dpa, flow); - - return ROCKER_OK; -} - -static int of_dpa_cmd_flow_get_stats(OfDpa *of_dpa, uint64_t cookie, - struct desc_info *info, char *buf) -{ - OfDpaFlow *flow = of_dpa_flow_find(of_dpa, cookie); - size_t tlv_size; - int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) / 1000; - int pos; - - if (!flow) { - return -ROCKER_ENOENT; - } - - tlv_size = rocker_tlv_total_size(sizeof(uint32_t)) + /* duration */ - rocker_tlv_total_size(sizeof(uint64_t)) + /* rx_pkts */ - rocker_tlv_total_size(sizeof(uint64_t)); /* tx_ptks */ - - if (tlv_size > desc_buf_size(info)) { - return -ROCKER_EMSGSIZE; - } - - pos = 0; - rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_OF_DPA_FLOW_STAT_DURATION, - (int32_t)(now - flow->stats.install_time)); - rocker_tlv_put_le64(buf, &pos, ROCKER_TLV_OF_DPA_FLOW_STAT_RX_PKTS, - flow->stats.rx_pkts); - rocker_tlv_put_le64(buf, &pos, ROCKER_TLV_OF_DPA_FLOW_STAT_TX_PKTS, - flow->stats.tx_pkts); - - return desc_set_buf(info, tlv_size); -} - -static int of_dpa_flow_cmd(OfDpa *of_dpa, struct desc_info *info, - char *buf, uint16_t cmd, - RockerTlv **flow_tlvs) -{ - uint64_t cookie; - - if (!flow_tlvs[ROCKER_TLV_OF_DPA_COOKIE]) { - return -ROCKER_EINVAL; - } - - cookie = rocker_tlv_get_le64(flow_tlvs[ROCKER_TLV_OF_DPA_COOKIE]); - - switch (cmd) { - case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD: - return of_dpa_cmd_flow_add(of_dpa, cookie, flow_tlvs); - case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD: - return of_dpa_cmd_flow_mod(of_dpa, cookie, flow_tlvs); - case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL: - return of_dpa_cmd_flow_del(of_dpa, cookie); - case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_GET_STATS: - return of_dpa_cmd_flow_get_stats(of_dpa, cookie, info, buf); - } - - return -ROCKER_ENOTSUP; -} - -static int of_dpa_cmd_add_l2_interface(OfDpaGroup *group, - RockerTlv **group_tlvs) -{ - if (!group_tlvs[ROCKER_TLV_OF_DPA_OUT_PPORT] || - !group_tlvs[ROCKER_TLV_OF_DPA_POP_VLAN]) { - return -ROCKER_EINVAL; - } - - group->l2_interface.out_pport = - rocker_tlv_get_le32(group_tlvs[ROCKER_TLV_OF_DPA_OUT_PPORT]); - group->l2_interface.pop_vlan = - rocker_tlv_get_u8(group_tlvs[ROCKER_TLV_OF_DPA_POP_VLAN]); - - return ROCKER_OK; -} - -static int of_dpa_cmd_add_l2_rewrite(OfDpa *of_dpa, OfDpaGroup *group, - RockerTlv **group_tlvs) -{ - OfDpaGroup *l2_interface_group; - - if (!group_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID_LOWER]) { - return -ROCKER_EINVAL; - } - - group->l2_rewrite.group_id = - rocker_tlv_get_le32(group_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID_LOWER]); - - l2_interface_group = of_dpa_group_find(of_dpa, group->l2_rewrite.group_id); - if (!l2_interface_group || - ROCKER_GROUP_TYPE_GET(l2_interface_group->id) != - ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE) { - DPRINTF("l2 rewrite group needs a valid l2 interface group\n"); - return -ROCKER_EINVAL; - } - - if (group_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC]) { - memcpy(group->l2_rewrite.src_mac.a, - rocker_tlv_data(group_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC]), - sizeof(group->l2_rewrite.src_mac.a)); - } - - if (group_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]) { - memcpy(group->l2_rewrite.dst_mac.a, - rocker_tlv_data(group_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]), - sizeof(group->l2_rewrite.dst_mac.a)); - } - - if (group_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]) { - group->l2_rewrite.vlan_id = - rocker_tlv_get_u16(group_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]); - if (ROCKER_GROUP_VLAN_GET(l2_interface_group->id) != - (ntohs(group->l2_rewrite.vlan_id) & VLAN_VID_MASK)) { - DPRINTF("Set VLAN ID must be same as L2 interface group\n"); - return -ROCKER_EINVAL; - } - } - - return ROCKER_OK; -} - -static int of_dpa_cmd_add_l2_flood(OfDpa *of_dpa, OfDpaGroup *group, - RockerTlv **group_tlvs) -{ - OfDpaGroup *l2_group; - RockerTlv **tlvs; - int err; - int i; - - if (!group_tlvs[ROCKER_TLV_OF_DPA_GROUP_COUNT] || - !group_tlvs[ROCKER_TLV_OF_DPA_GROUP_IDS]) { - return -ROCKER_EINVAL; - } - - group->l2_flood.group_count = - rocker_tlv_get_le16(group_tlvs[ROCKER_TLV_OF_DPA_GROUP_COUNT]); - - tlvs = g_new0(RockerTlv *, group->l2_flood.group_count + 1); - if (!tlvs) { - return -ROCKER_ENOMEM; - } - - g_free(group->l2_flood.group_ids); - group->l2_flood.group_ids = - g_new0(uint32_t, group->l2_flood.group_count); - if (!group->l2_flood.group_ids) { - err = -ROCKER_ENOMEM; - goto err_out; - } - - rocker_tlv_parse_nested(tlvs, group->l2_flood.group_count, - group_tlvs[ROCKER_TLV_OF_DPA_GROUP_IDS]); - - for (i = 0; i < group->l2_flood.group_count; i++) { - group->l2_flood.group_ids[i] = rocker_tlv_get_le32(tlvs[i + 1]); - } - - /* All of the L2 interface groups referenced by the L2 flood - * must have same VLAN - */ - - for (i = 0; i < group->l2_flood.group_count; i++) { - l2_group = of_dpa_group_find(of_dpa, group->l2_flood.group_ids[i]); - if (!l2_group) { - continue; - } - if ((ROCKER_GROUP_TYPE_GET(l2_group->id) == - ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE) && - (ROCKER_GROUP_VLAN_GET(l2_group->id) != - ROCKER_GROUP_VLAN_GET(group->id))) { - DPRINTF("l2 interface group 0x%08x VLAN doesn't match l2 " - "flood group 0x%08x\n", - group->l2_flood.group_ids[i], group->id); - err = -ROCKER_EINVAL; - goto err_out; - } - } - - g_free(tlvs); - return ROCKER_OK; - -err_out: - group->l2_flood.group_count = 0; - g_free(group->l2_flood.group_ids); - g_free(tlvs); - - return err; -} - -static int of_dpa_cmd_add_l3_unicast(OfDpaGroup *group, RockerTlv **group_tlvs) -{ - if (!group_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID_LOWER]) { - return -ROCKER_EINVAL; - } - - group->l3_unicast.group_id = - rocker_tlv_get_le32(group_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID_LOWER]); - - if (group_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC]) { - memcpy(group->l3_unicast.src_mac.a, - rocker_tlv_data(group_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC]), - sizeof(group->l3_unicast.src_mac.a)); - } - - if (group_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]) { - memcpy(group->l3_unicast.dst_mac.a, - rocker_tlv_data(group_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]), - sizeof(group->l3_unicast.dst_mac.a)); - } - - if (group_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]) { - group->l3_unicast.vlan_id = - rocker_tlv_get_u16(group_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]); - } - - if (group_tlvs[ROCKER_TLV_OF_DPA_TTL_CHECK]) { - group->l3_unicast.ttl_check = - rocker_tlv_get_u8(group_tlvs[ROCKER_TLV_OF_DPA_TTL_CHECK]); - } - - return ROCKER_OK; -} - -static int of_dpa_cmd_group_do(OfDpa *of_dpa, uint32_t group_id, - OfDpaGroup *group, RockerTlv **group_tlvs) -{ - uint8_t type = ROCKER_GROUP_TYPE_GET(group_id); - - switch (type) { - case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE: - return of_dpa_cmd_add_l2_interface(group, group_tlvs); - case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE: - return of_dpa_cmd_add_l2_rewrite(of_dpa, group, group_tlvs); - case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD: - /* Treat L2 multicast group same as a L2 flood group */ - case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST: - return of_dpa_cmd_add_l2_flood(of_dpa, group, group_tlvs); - case ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST: - return of_dpa_cmd_add_l3_unicast(group, group_tlvs); - } - - return -ROCKER_ENOTSUP; -} - -static int of_dpa_cmd_group_add(OfDpa *of_dpa, uint32_t group_id, - RockerTlv **group_tlvs) -{ - OfDpaGroup *group = of_dpa_group_find(of_dpa, group_id); - int err; - - if (group) { - return -ROCKER_EEXIST; - } - - group = of_dpa_group_alloc(group_id); - if (!group) { - return -ROCKER_ENOMEM; - } - - err = of_dpa_cmd_group_do(of_dpa, group_id, group, group_tlvs); - if (err) { - goto err_cmd_add; - } - - err = of_dpa_group_add(of_dpa, group); - if (err) { - goto err_cmd_add; - } - - return ROCKER_OK; - -err_cmd_add: - g_free(group); - return err; -} - -static int of_dpa_cmd_group_mod(OfDpa *of_dpa, uint32_t group_id, - RockerTlv **group_tlvs) -{ - OfDpaGroup *group = of_dpa_group_find(of_dpa, group_id); - - if (!group) { - return -ROCKER_ENOENT; - } - - return of_dpa_cmd_group_do(of_dpa, group_id, group, group_tlvs); -} - -static int of_dpa_cmd_group_del(OfDpa *of_dpa, uint32_t group_id) -{ - OfDpaGroup *group = of_dpa_group_find(of_dpa, group_id); - - if (!group) { - return -ROCKER_ENOENT; - } - - return of_dpa_group_del(of_dpa, group); -} - -static int of_dpa_cmd_group_get_stats(OfDpa *of_dpa, uint32_t group_id, - struct desc_info *info, char *buf) -{ - return -ROCKER_ENOTSUP; -} - -static int of_dpa_group_cmd(OfDpa *of_dpa, struct desc_info *info, - char *buf, uint16_t cmd, RockerTlv **group_tlvs) -{ - uint32_t group_id; - - if (!group_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]) { - return -ROCKER_EINVAL; - } - - group_id = rocker_tlv_get_le32(group_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]); - - switch (cmd) { - case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD: - return of_dpa_cmd_group_add(of_dpa, group_id, group_tlvs); - case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD: - return of_dpa_cmd_group_mod(of_dpa, group_id, group_tlvs); - case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL: - return of_dpa_cmd_group_del(of_dpa, group_id); - case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS: - return of_dpa_cmd_group_get_stats(of_dpa, group_id, info, buf); - } - - return -ROCKER_ENOTSUP; -} - -static int of_dpa_cmd(World *world, struct desc_info *info, - char *buf, uint16_t cmd, RockerTlv *cmd_info_tlv) -{ - OfDpa *of_dpa = world_private(world); - RockerTlv *tlvs[ROCKER_TLV_OF_DPA_MAX + 1]; - - rocker_tlv_parse_nested(tlvs, ROCKER_TLV_OF_DPA_MAX, cmd_info_tlv); - - switch (cmd) { - case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD: - case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD: - case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL: - case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_GET_STATS: - return of_dpa_flow_cmd(of_dpa, info, buf, cmd, tlvs); - case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD: - case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD: - case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL: - case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS: - return of_dpa_group_cmd(of_dpa, info, buf, cmd, tlvs); - } - - return -ROCKER_ENOTSUP; -} - -static gboolean rocker_int64_equal(gconstpointer v1, gconstpointer v2) -{ - return *((const uint64_t *)v1) == *((const uint64_t *)v2); -} - -static guint rocker_int64_hash(gconstpointer v) -{ - return (guint)*(const uint64_t *)v; -} - -static int of_dpa_init(World *world) -{ - OfDpa *of_dpa = world_private(world); - - of_dpa->world = world; - - of_dpa->flow_tbl = g_hash_table_new_full(rocker_int64_hash, - rocker_int64_equal, - NULL, g_free); - if (!of_dpa->flow_tbl) { - return -ENOMEM; - } - - of_dpa->group_tbl = g_hash_table_new_full(g_int_hash, g_int_equal, - NULL, g_free); - if (!of_dpa->group_tbl) { - goto err_group_tbl; - } - - /* XXX hardcode some artificial table max values */ - of_dpa->flow_tbl_max_size = 100; - of_dpa->group_tbl_max_size = 100; - - return 0; - -err_group_tbl: - g_hash_table_destroy(of_dpa->flow_tbl); - return -ENOMEM; -} - -static void of_dpa_uninit(World *world) -{ - OfDpa *of_dpa = world_private(world); - - g_hash_table_destroy(of_dpa->group_tbl); - g_hash_table_destroy(of_dpa->flow_tbl); -} - -struct of_dpa_flow_fill_context { - RockerOfDpaFlowList *list; - uint32_t tbl_id; -}; - -static void of_dpa_flow_fill(void *cookie, void *value, void *user_data) -{ - struct of_dpa_flow *flow = value; - struct of_dpa_flow_key *key = &flow->key; - struct of_dpa_flow_key *mask = &flow->mask; - struct of_dpa_flow_fill_context *flow_context = user_data; - RockerOfDpaFlowList *new; - RockerOfDpaFlow *nflow; - RockerOfDpaFlowKey *nkey; - RockerOfDpaFlowMask *nmask; - RockerOfDpaFlowAction *naction; - - if (flow_context->tbl_id != -1 && - flow_context->tbl_id != key->tbl_id) { - return; - } - - new = g_malloc0(sizeof(*new)); - nflow = new->value = g_malloc0(sizeof(*nflow)); - nkey = nflow->key = g_malloc0(sizeof(*nkey)); - nmask = nflow->mask = g_malloc0(sizeof(*nmask)); - naction = nflow->action = g_malloc0(sizeof(*naction)); - - nflow->cookie = flow->cookie; - nflow->hits = flow->stats.hits; - nkey->priority = flow->priority; - nkey->tbl_id = key->tbl_id; - - if (key->in_pport || mask->in_pport) { - nkey->has_in_pport = true; - nkey->in_pport = key->in_pport; - } - - if (nkey->has_in_pport && mask->in_pport != 0xffffffff) { - nmask->has_in_pport = true; - nmask->in_pport = mask->in_pport; - } - - if (key->eth.vlan_id || mask->eth.vlan_id) { - nkey->has_vlan_id = true; - nkey->vlan_id = ntohs(key->eth.vlan_id); - } - - if (nkey->has_vlan_id && mask->eth.vlan_id != 0xffff) { - nmask->has_vlan_id = true; - nmask->vlan_id = ntohs(mask->eth.vlan_id); - } - - if (key->tunnel_id || mask->tunnel_id) { - nkey->has_tunnel_id = true; - nkey->tunnel_id = key->tunnel_id; - } - - if (nkey->has_tunnel_id && mask->tunnel_id != 0xffffffff) { - nmask->has_tunnel_id = true; - nmask->tunnel_id = mask->tunnel_id; - } - - if (memcmp(key->eth.src.a, zero_mac.a, ETH_ALEN) || - memcmp(mask->eth.src.a, zero_mac.a, ETH_ALEN)) { - nkey->has_eth_src = true; - nkey->eth_src = qemu_mac_strdup_printf(key->eth.src.a); - } - - if (nkey->has_eth_src && memcmp(mask->eth.src.a, ff_mac.a, ETH_ALEN)) { - nmask->has_eth_src = true; - nmask->eth_src = qemu_mac_strdup_printf(mask->eth.src.a); - } - - if (memcmp(key->eth.dst.a, zero_mac.a, ETH_ALEN) || - memcmp(mask->eth.dst.a, zero_mac.a, ETH_ALEN)) { - nkey->has_eth_dst = true; - nkey->eth_dst = qemu_mac_strdup_printf(key->eth.dst.a); - } - - if (nkey->has_eth_dst && memcmp(mask->eth.dst.a, ff_mac.a, ETH_ALEN)) { - nmask->has_eth_dst = true; - nmask->eth_dst = qemu_mac_strdup_printf(mask->eth.dst.a); - } - - if (key->eth.type) { - - nkey->has_eth_type = true; - nkey->eth_type = ntohs(key->eth.type); - - switch (ntohs(key->eth.type)) { - case 0x0800: - case 0x86dd: - if (key->ip.proto || mask->ip.proto) { - nkey->has_ip_proto = true; - nkey->ip_proto = key->ip.proto; - } - if (nkey->has_ip_proto && mask->ip.proto != 0xff) { - nmask->has_ip_proto = true; - nmask->ip_proto = mask->ip.proto; - } - if (key->ip.tos || mask->ip.tos) { - nkey->has_ip_tos = true; - nkey->ip_tos = key->ip.tos; - } - if (nkey->has_ip_tos && mask->ip.tos != 0xff) { - nmask->has_ip_tos = true; - nmask->ip_tos = mask->ip.tos; - } - break; - } - - switch (ntohs(key->eth.type)) { - case 0x0800: - if (key->ipv4.addr.dst || mask->ipv4.addr.dst) { - char *dst = inet_ntoa(*(struct in_addr *)&key->ipv4.addr.dst); - int dst_len = of_dpa_mask2prefix(mask->ipv4.addr.dst); - nkey->has_ip_dst = true; - nkey->ip_dst = g_strdup_printf("%s/%d", dst, dst_len); - } - break; - } - } - - if (flow->action.goto_tbl) { - naction->has_goto_tbl = true; - naction->goto_tbl = flow->action.goto_tbl; - } - - if (flow->action.write.group_id) { - naction->has_group_id = true; - naction->group_id = flow->action.write.group_id; - } - - if (flow->action.apply.new_vlan_id) { - naction->has_new_vlan_id = true; - naction->new_vlan_id = flow->action.apply.new_vlan_id; - } - - new->next = flow_context->list; - flow_context->list = new; -} - -RockerOfDpaFlowList *qmp_query_rocker_of_dpa_flows(const char *name, - bool has_tbl_id, - uint32_t tbl_id, - Error **errp) -{ - struct rocker *r; - struct world *w; - struct of_dpa *of_dpa; - struct of_dpa_flow_fill_context fill_context = { - .list = NULL, - .tbl_id = tbl_id, - }; - - r = rocker_find(name); - if (!r) { - error_setg(errp, "rocker %s not found", name); - return NULL; - } - - w = rocker_get_world(r, ROCKER_WORLD_TYPE_OF_DPA); - if (!w) { - error_setg(errp, "rocker %s doesn't have OF-DPA world", name); - return NULL; - } - - of_dpa = world_private(w); - - g_hash_table_foreach(of_dpa->flow_tbl, of_dpa_flow_fill, &fill_context); - - return fill_context.list; -} - -struct of_dpa_group_fill_context { - RockerOfDpaGroupList *list; - uint8_t type; -}; - -static void of_dpa_group_fill(void *key, void *value, void *user_data) -{ - struct of_dpa_group *group = value; - struct of_dpa_group_fill_context *flow_context = user_data; - RockerOfDpaGroupList *new; - RockerOfDpaGroup *ngroup; - struct uint32List *id; - int i; - - if (flow_context->type != 9 && - flow_context->type != ROCKER_GROUP_TYPE_GET(group->id)) { - return; - } - - new = g_malloc0(sizeof(*new)); - ngroup = new->value = g_malloc0(sizeof(*ngroup)); - - ngroup->id = group->id; - - ngroup->type = ROCKER_GROUP_TYPE_GET(group->id); - - switch (ngroup->type) { - case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE: - ngroup->has_vlan_id = true; - ngroup->vlan_id = ROCKER_GROUP_VLAN_GET(group->id); - ngroup->has_pport = true; - ngroup->pport = ROCKER_GROUP_PORT_GET(group->id); - ngroup->has_out_pport = true; - ngroup->out_pport = group->l2_interface.out_pport; - ngroup->has_pop_vlan = true; - ngroup->pop_vlan = group->l2_interface.pop_vlan; - break; - case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE: - ngroup->has_index = true; - ngroup->index = ROCKER_GROUP_INDEX_LONG_GET(group->id); - ngroup->has_group_id = true; - ngroup->group_id = group->l2_rewrite.group_id; - if (group->l2_rewrite.vlan_id) { - ngroup->has_set_vlan_id = true; - ngroup->set_vlan_id = ntohs(group->l2_rewrite.vlan_id); - } - if (memcmp(group->l2_rewrite.src_mac.a, zero_mac.a, ETH_ALEN)) { - ngroup->has_set_eth_src = true; - ngroup->set_eth_src = - qemu_mac_strdup_printf(group->l2_rewrite.src_mac.a); - } - if (memcmp(group->l2_rewrite.dst_mac.a, zero_mac.a, ETH_ALEN)) { - ngroup->has_set_eth_dst = true; - ngroup->set_eth_dst = - qemu_mac_strdup_printf(group->l2_rewrite.dst_mac.a); - } - break; - case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD: - case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST: - ngroup->has_vlan_id = true; - ngroup->vlan_id = ROCKER_GROUP_VLAN_GET(group->id); - ngroup->has_index = true; - ngroup->index = ROCKER_GROUP_INDEX_GET(group->id); - for (i = 0; i < group->l2_flood.group_count; i++) { - ngroup->has_group_ids = true; - id = g_malloc0(sizeof(*id)); - id->value = group->l2_flood.group_ids[i]; - id->next = ngroup->group_ids; - ngroup->group_ids = id; - } - break; - case ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST: - ngroup->has_index = true; - ngroup->index = ROCKER_GROUP_INDEX_LONG_GET(group->id); - ngroup->has_group_id = true; - ngroup->group_id = group->l3_unicast.group_id; - if (group->l3_unicast.vlan_id) { - ngroup->has_set_vlan_id = true; - ngroup->set_vlan_id = ntohs(group->l3_unicast.vlan_id); - } - if (memcmp(group->l3_unicast.src_mac.a, zero_mac.a, ETH_ALEN)) { - ngroup->has_set_eth_src = true; - ngroup->set_eth_src = - qemu_mac_strdup_printf(group->l3_unicast.src_mac.a); - } - if (memcmp(group->l3_unicast.dst_mac.a, zero_mac.a, ETH_ALEN)) { - ngroup->has_set_eth_dst = true; - ngroup->set_eth_dst = - qemu_mac_strdup_printf(group->l3_unicast.dst_mac.a); - } - if (group->l3_unicast.ttl_check) { - ngroup->has_ttl_check = true; - ngroup->ttl_check = group->l3_unicast.ttl_check; - } - break; - } - - new->next = flow_context->list; - flow_context->list = new; -} - -RockerOfDpaGroupList *qmp_query_rocker_of_dpa_groups(const char *name, - bool has_type, - uint8_t type, - Error **errp) -{ - struct rocker *r; - struct world *w; - struct of_dpa *of_dpa; - struct of_dpa_group_fill_context fill_context = { - .list = NULL, - .type = type, - }; - - r = rocker_find(name); - if (!r) { - error_setg(errp, "rocker %s not found", name); - return NULL; - } - - w = rocker_get_world(r, ROCKER_WORLD_TYPE_OF_DPA); - if (!w) { - error_setg(errp, "rocker %s doesn't have OF-DPA world", name); - return NULL; - } - - of_dpa = world_private(w); - - g_hash_table_foreach(of_dpa->group_tbl, of_dpa_group_fill, &fill_context); - - return fill_context.list; -} - -static WorldOps of_dpa_ops = { - .name = "ofdpa", - .init = of_dpa_init, - .uninit = of_dpa_uninit, - .ig = of_dpa_ig, - .cmd = of_dpa_cmd, -}; - -World *of_dpa_world_alloc(Rocker *r) -{ - return world_alloc(r, sizeof(OfDpa), ROCKER_WORLD_TYPE_OF_DPA, &of_dpa_ops); -} diff --git a/qemu/hw/net/rocker/rocker_of_dpa.h b/qemu/hw/net/rocker/rocker_of_dpa.h deleted file mode 100644 index f3f6d7780..000000000 --- a/qemu/hw/net/rocker/rocker_of_dpa.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * QEMU rocker switch emulation - OF-DPA flow processing support - * - * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _ROCKER_OF_DPA_H_ -#define _ROCKER_OF_DPA_H_ - -World *of_dpa_world_alloc(Rocker *r); - -#endif /* _ROCKER_OF_DPA_H_ */ diff --git a/qemu/hw/net/rocker/rocker_tlv.h b/qemu/hw/net/rocker/rocker_tlv.h deleted file mode 100644 index e3c4ab679..000000000 --- a/qemu/hw/net/rocker/rocker_tlv.h +++ /dev/null @@ -1,244 +0,0 @@ -/* - * QEMU rocker switch emulation - TLV parsing and composing - * - * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _ROCKER_TLV_H_ -#define _ROCKER_TLV_H_ - -#define ROCKER_TLV_ALIGNTO 8U -#define ROCKER_TLV_ALIGN(len) \ - (((len) + ROCKER_TLV_ALIGNTO - 1) & ~(ROCKER_TLV_ALIGNTO - 1)) -#define ROCKER_TLV_HDRLEN ROCKER_TLV_ALIGN(sizeof(RockerTlv)) - -/* - * <------- ROCKER_TLV_HDRLEN -------> <--- ROCKER_TLV_ALIGN(payload) ---> - * +-----------------------------+- - -+- - - - - - - - - - - - - - -+- - -+ - * | Header | Pad | Payload | Pad | - * | (RockerTlv) | ing | | ing | - * +-----------------------------+- - -+- - - - - - - - - - - - - - -+- - -+ - * <--------------------------- tlv->len --------------------------> - */ - -static inline RockerTlv *rocker_tlv_next(const RockerTlv *tlv, int *remaining) -{ - int totlen = ROCKER_TLV_ALIGN(le16_to_cpu(tlv->len)); - - *remaining -= totlen; - return (RockerTlv *) ((char *) tlv + totlen); -} - -static inline int rocker_tlv_ok(const RockerTlv *tlv, int remaining) -{ - return remaining >= (int) ROCKER_TLV_HDRLEN && - le16_to_cpu(tlv->len) >= ROCKER_TLV_HDRLEN && - le16_to_cpu(tlv->len) <= remaining; -} - -#define rocker_tlv_for_each(pos, head, len, rem) \ - for (pos = head, rem = len; \ - rocker_tlv_ok(pos, rem); \ - pos = rocker_tlv_next(pos, &(rem))) - -#define rocker_tlv_for_each_nested(pos, tlv, rem) \ - rocker_tlv_for_each(pos, rocker_tlv_data(tlv), rocker_tlv_len(tlv), rem) - -static inline int rocker_tlv_size(int payload) -{ - return ROCKER_TLV_HDRLEN + payload; -} - -static inline int rocker_tlv_total_size(int payload) -{ - return ROCKER_TLV_ALIGN(rocker_tlv_size(payload)); -} - -static inline int rocker_tlv_padlen(int payload) -{ - return rocker_tlv_total_size(payload) - rocker_tlv_size(payload); -} - -static inline int rocker_tlv_type(const RockerTlv *tlv) -{ - return le32_to_cpu(tlv->type); -} - -static inline void *rocker_tlv_data(const RockerTlv *tlv) -{ - return (char *) tlv + ROCKER_TLV_HDRLEN; -} - -static inline int rocker_tlv_len(const RockerTlv *tlv) -{ - return le16_to_cpu(tlv->len) - ROCKER_TLV_HDRLEN; -} - -static inline uint8_t rocker_tlv_get_u8(const RockerTlv *tlv) -{ - return *(uint8_t *) rocker_tlv_data(tlv); -} - -static inline uint16_t rocker_tlv_get_u16(const RockerTlv *tlv) -{ - return *(uint16_t *) rocker_tlv_data(tlv); -} - -static inline uint32_t rocker_tlv_get_u32(const RockerTlv *tlv) -{ - return *(uint32_t *) rocker_tlv_data(tlv); -} - -static inline uint64_t rocker_tlv_get_u64(const RockerTlv *tlv) -{ - return *(uint64_t *) rocker_tlv_data(tlv); -} - -static inline uint16_t rocker_tlv_get_le16(const RockerTlv *tlv) -{ - return le16_to_cpup((uint16_t *) rocker_tlv_data(tlv)); -} - -static inline uint32_t rocker_tlv_get_le32(const RockerTlv *tlv) -{ - return le32_to_cpup((uint32_t *) rocker_tlv_data(tlv)); -} - -static inline uint64_t rocker_tlv_get_le64(const RockerTlv *tlv) -{ - return le64_to_cpup((uint64_t *) rocker_tlv_data(tlv)); -} - -static inline void rocker_tlv_parse(RockerTlv **tb, int maxtype, - const char *buf, int buf_len) -{ - const RockerTlv *tlv; - const RockerTlv *head = (const RockerTlv *) buf; - int rem; - - memset(tb, 0, sizeof(RockerTlv *) * (maxtype + 1)); - - rocker_tlv_for_each(tlv, head, buf_len, rem) { - uint32_t type = rocker_tlv_type(tlv); - - if (type > 0 && type <= maxtype) { - tb[type] = (RockerTlv *) tlv; - } - } -} - -static inline void rocker_tlv_parse_nested(RockerTlv **tb, int maxtype, - const RockerTlv *tlv) -{ - rocker_tlv_parse(tb, maxtype, rocker_tlv_data(tlv), rocker_tlv_len(tlv)); -} - -static inline RockerTlv *rocker_tlv_start(char *buf, int buf_pos) -{ - return (RockerTlv *) (buf + buf_pos); -} - -static inline void rocker_tlv_put_iov(char *buf, int *buf_pos, - int type, const struct iovec *iov, - const unsigned int iovcnt) -{ - size_t len = iov_size(iov, iovcnt); - int total_size = rocker_tlv_total_size(len); - RockerTlv *tlv; - - tlv = rocker_tlv_start(buf, *buf_pos); - *buf_pos += total_size; - tlv->type = cpu_to_le32(type); - tlv->len = cpu_to_le16(rocker_tlv_size(len)); - iov_to_buf(iov, iovcnt, 0, rocker_tlv_data(tlv), len); - memset((char *) tlv + le16_to_cpu(tlv->len), 0, rocker_tlv_padlen(len)); -} - -static inline void rocker_tlv_put(char *buf, int *buf_pos, - int type, int len, void *data) -{ - struct iovec iov = { - .iov_base = data, - .iov_len = len, - }; - - rocker_tlv_put_iov(buf, buf_pos, type, &iov, 1); -} - -static inline void rocker_tlv_put_u8(char *buf, int *buf_pos, - int type, uint8_t value) -{ - rocker_tlv_put(buf, buf_pos, type, sizeof(uint8_t), &value); -} - -static inline void rocker_tlv_put_u16(char *buf, int *buf_pos, - int type, uint16_t value) -{ - rocker_tlv_put(buf, buf_pos, type, sizeof(uint16_t), &value); -} - -static inline void rocker_tlv_put_u32(char *buf, int *buf_pos, - int type, uint32_t value) -{ - rocker_tlv_put(buf, buf_pos, type, sizeof(uint32_t), &value); -} - -static inline void rocker_tlv_put_u64(char *buf, int *buf_pos, - int type, uint64_t value) -{ - rocker_tlv_put(buf, buf_pos, type, sizeof(uint64_t), &value); -} - -static inline void rocker_tlv_put_le16(char *buf, int *buf_pos, - int type, uint16_t value) -{ - value = cpu_to_le16(value); - rocker_tlv_put(buf, buf_pos, type, sizeof(uint16_t), &value); -} - -static inline void rocker_tlv_put_le32(char *buf, int *buf_pos, - int type, uint32_t value) -{ - value = cpu_to_le32(value); - rocker_tlv_put(buf, buf_pos, type, sizeof(uint32_t), &value); -} - -static inline void rocker_tlv_put_le64(char *buf, int *buf_pos, - int type, uint64_t value) -{ - value = cpu_to_le64(value); - rocker_tlv_put(buf, buf_pos, type, sizeof(uint64_t), &value); -} - -static inline RockerTlv *rocker_tlv_nest_start(char *buf, int *buf_pos, - int type) -{ - RockerTlv *start = rocker_tlv_start(buf, *buf_pos); - - rocker_tlv_put(buf, buf_pos, type, 0, NULL); - return start; -} - -static inline void rocker_tlv_nest_end(char *buf, int *buf_pos, - RockerTlv *start) -{ - start->len = (char *) rocker_tlv_start(buf, *buf_pos) - (char *) start; -} - -static inline void rocker_tlv_nest_cancel(char *buf, int *buf_pos, - RockerTlv *start) -{ - *buf_pos = (char *) start - buf; -} - -#endif diff --git a/qemu/hw/net/rocker/rocker_world.c b/qemu/hw/net/rocker/rocker_world.c deleted file mode 100644 index 89777e968..000000000 --- a/qemu/hw/net/rocker/rocker_world.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * QEMU rocker switch emulation - switch worlds - * - * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "qemu/osdep.h" -#include "qemu/iov.h" - -#include "rocker.h" -#include "rocker_world.h" - -struct world { - Rocker *r; - enum rocker_world_type type; - WorldOps *ops; -}; - -ssize_t world_ingress(World *world, uint32_t pport, - const struct iovec *iov, int iovcnt) -{ - if (world->ops->ig) { - return world->ops->ig(world, pport, iov, iovcnt); - } - - return -1; -} - -int world_do_cmd(World *world, DescInfo *info, - char *buf, uint16_t cmd, RockerTlv *cmd_info_tlv) -{ - if (world->ops->cmd) { - return world->ops->cmd(world, info, buf, cmd, cmd_info_tlv); - } - - return -ROCKER_ENOTSUP; -} - -World *world_alloc(Rocker *r, size_t sizeof_private, - enum rocker_world_type type, WorldOps *ops) -{ - World *w = g_malloc0(sizeof(World) + sizeof_private); - - if (w) { - w->r = r; - w->type = type; - w->ops = ops; - if (w->ops->init) { - w->ops->init(w); - } - } - - return w; -} - -void world_free(World *world) -{ - if (world->ops->uninit) { - world->ops->uninit(world); - } - g_free(world); -} - -void world_reset(World *world) -{ - if (world->ops->uninit) { - world->ops->uninit(world); - } - if (world->ops->init) { - world->ops->init(world); - } -} - -void *world_private(World *world) -{ - return world + 1; -} - -Rocker *world_rocker(World *world) -{ - return world->r; -} - -enum rocker_world_type world_type(World *world) -{ - return world->type; -} - -const char *world_name(World *world) -{ - return world->ops->name; -} diff --git a/qemu/hw/net/rocker/rocker_world.h b/qemu/hw/net/rocker/rocker_world.h deleted file mode 100644 index 58ade4733..000000000 --- a/qemu/hw/net/rocker/rocker_world.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * QEMU rocker switch emulation - switch worlds - * - * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _ROCKER_WORLD_H_ -#define _ROCKER_WORLD_H_ - -#include "rocker_hw.h" - -enum rocker_world_type { - ROCKER_WORLD_TYPE_OF_DPA = ROCKER_PORT_MODE_OF_DPA, - ROCKER_WORLD_TYPE_MAX, -}; - -typedef int (world_init)(World *world); -typedef void (world_uninit)(World *world); -typedef ssize_t (world_ig)(World *world, uint32_t pport, - const struct iovec *iov, int iovcnt); -typedef int (world_cmd)(World *world, DescInfo *info, - char *buf, uint16_t cmd, - RockerTlv *cmd_info_tlv); - -typedef struct world_ops { - const char *name; - world_init *init; - world_uninit *uninit; - world_ig *ig; - world_cmd *cmd; -} WorldOps; - -ssize_t world_ingress(World *world, uint32_t pport, - const struct iovec *iov, int iovcnt); -int world_do_cmd(World *world, DescInfo *info, - char *buf, uint16_t cmd, RockerTlv *cmd_info_tlv); - -World *world_alloc(Rocker *r, size_t sizeof_private, - enum rocker_world_type type, WorldOps *ops); -void world_free(World *world); -void world_reset(World *world); - -void *world_private(World *world); -Rocker *world_rocker(World *world); - -enum rocker_world_type world_type(World *world); -const char *world_name(World *world); - -World *rocker_get_world(Rocker *r, enum rocker_world_type type); - -#endif /* _ROCKER_WORLD_H_ */ |