/* SPDX-License-Identifier: BSD-3-Clause * Copyright(c) 2022 Corigine, Inc. * All rights reserved. */ #include "../nfpcore/nfp_nsp.h" #include "../nfp_logs.h" #include "../nfp_common.h" #include "../nfp_flow.h" #include "nfp_flower.h" #include "nfp_flower_cmsg.h" #include "nfp_flower_ctrl.h" #include "nfp_flower_representor.h" static void * nfp_flower_cmsg_init(struct rte_mbuf *m, enum nfp_flower_cmsg_type type, uint32_t size) { char *pkt; uint32_t data; uint32_t new_size = size; struct nfp_flower_cmsg_hdr *hdr; pkt = rte_pktmbuf_mtod(m, char *); PMD_DRV_LOG(DEBUG, "flower_cmsg_init using pkt at %p", pkt); data = rte_cpu_to_be_32(NFP_NET_META_PORTID); rte_memcpy(pkt, &data, 4); pkt += 4; new_size += 4; /* First the metadata as flower requires it */ data = rte_cpu_to_be_32(NFP_META_PORT_ID_CTRL); rte_memcpy(pkt, &data, 4); pkt += 4; new_size += 4; /* Now the ctrl header */ hdr = (struct nfp_flower_cmsg_hdr *)pkt; hdr->pad = 0; hdr->type = type; hdr->version = NFP_FLOWER_CMSG_VER1; pkt = (char *)hdr + NFP_FLOWER_CMSG_HLEN; new_size += NFP_FLOWER_CMSG_HLEN; m->pkt_len = new_size; m->data_len = m->pkt_len; return pkt; } static void nfp_flower_cmsg_mac_repr_init(struct rte_mbuf *mbuf, int num_ports) { uint32_t size; struct nfp_flower_cmsg_mac_repr *msg; enum nfp_flower_cmsg_type type = NFP_FLOWER_CMSG_TYPE_MAC_REPR; size = sizeof(*msg) + (num_ports * sizeof(msg->ports[0])); msg = nfp_flower_cmsg_init(mbuf, type, size); memset(msg->reserved, 0, sizeof(msg->reserved)); msg->num_ports = num_ports; } static void nfp_flower_cmsg_mac_repr_fill(struct rte_mbuf *m, unsigned int idx, unsigned int nbi, unsigned int nbi_port, unsigned int phys_port) { struct nfp_flower_cmsg_mac_repr *msg; msg = (struct nfp_flower_cmsg_mac_repr *)nfp_flower_cmsg_get_data(m); msg->ports[idx].idx = idx; msg->ports[idx].info = nbi & NFP_FLOWER_CMSG_MAC_REPR_NBI; msg->ports[idx].nbi_port = nbi_port; msg->ports[idx].phys_port = phys_port; } int nfp_flower_cmsg_mac_repr(struct nfp_app_fw_flower *app_fw_flower) { int i; uint16_t cnt; unsigned int nbi; unsigned int nbi_port; unsigned int phys_port; struct rte_mbuf *mbuf; struct nfp_eth_table *nfp_eth_table; mbuf = rte_pktmbuf_alloc(app_fw_flower->ctrl_pktmbuf_pool); if (mbuf == NULL) { PMD_DRV_LOG(ERR, "Could not allocate mac repr cmsg"); return -ENOMEM; } nfp_flower_cmsg_mac_repr_init(mbuf, app_fw_flower->num_phyport_reprs); /* Fill in the mac repr cmsg */ nfp_eth_table = app_fw_flower->pf_hw->pf_dev->nfp_eth_table; for (i = 0; i < app_fw_flower->num_phyport_reprs; i++) { nbi = nfp_eth_table->ports[i].nbi; nbi_port = nfp_eth_table->ports[i].base; phys_port = nfp_eth_table->ports[i].index; nfp_flower_cmsg_mac_repr_fill(mbuf, i, nbi, nbi_port, phys_port); } /* Send the cmsg via the ctrl vNIC */ cnt = nfp_flower_ctrl_vnic_xmit(app_fw_flower, mbuf); if (cnt == 0) { PMD_DRV_LOG(ERR, "Send cmsg through ctrl vnic failed."); rte_pktmbuf_free(mbuf); return -EIO; } return 0; } int nfp_flower_cmsg_repr_reify(struct nfp_app_fw_flower *app_fw_flower, struct nfp_flower_representor *repr) { uint16_t cnt; struct rte_mbuf *mbuf; struct nfp_flower_cmsg_port_reify *msg; mbuf = rte_pktmbuf_alloc(app_fw_flower->ctrl_pktmbuf_pool); if (mbuf == NULL) { PMD_DRV_LOG(DEBUG, "alloc mbuf for repr reify failed"); return -ENOMEM; } msg = nfp_flower_cmsg_init(mbuf, NFP_FLOWER_CMSG_TYPE_PORT_REIFY, sizeof(*msg)); msg->portnum = rte_cpu_to_be_32(repr->port_id); msg->reserved = 0; msg->info = rte_cpu_to_be_16(1); cnt = nfp_flower_ctrl_vnic_xmit(app_fw_flower, mbuf); if (cnt == 0) { PMD_DRV_LOG(ERR, "Send cmsg through ctrl vnic failed."); rte_pktmbuf_free(mbuf); return -EIO; } return 0; } int nfp_flower_cmsg_port_mod(struct nfp_app_fw_flower *app_fw_flower, uint32_t port_id, bool carrier_ok) { uint16_t cnt; struct rte_mbuf *mbuf; struct nfp_flower_cmsg_port_mod *msg; mbuf = rte_pktmbuf_alloc(app_fw_flower->ctrl_pktmbuf_pool); if (mbuf == NULL) { PMD_DRV_LOG(DEBUG, "alloc mbuf for repr portmod failed"); return -ENOMEM; } msg = nfp_flower_cmsg_init(mbuf, NFP_FLOWER_CMSG_TYPE_PORT_MOD, sizeof(*msg)); msg->portnum = rte_cpu_to_be_32(port_id); msg->reserved = 0; msg->info = carrier_ok; msg->mtu = 9000; cnt = nfp_flower_ctrl_vnic_xmit(app_fw_flower, mbuf); if (cnt == 0) { PMD_DRV_LOG(ERR, "Send cmsg through ctrl vnic failed."); rte_pktmbuf_free(mbuf); return -EIO; } return 0; } int nfp_flower_cmsg_flow_delete(struct nfp_app_fw_flower *app_fw_flower, struct rte_flow *flow) { char *msg; uint16_t cnt; uint32_t msg_len; struct rte_mbuf *mbuf; struct nfp_fl_rule_metadata *nfp_flow_meta; mbuf = rte_pktmbuf_alloc(app_fw_flower->ctrl_pktmbuf_pool); if (mbuf == NULL) { PMD_DRV_LOG(DEBUG, "Failed to alloc mbuf for flow delete."); return -ENOMEM; } /* Copy the flow to mbuf */ nfp_flow_meta = flow->payload.meta; msg_len = (nfp_flow_meta->key_len + nfp_flow_meta->mask_len + nfp_flow_meta->act_len) << NFP_FL_LW_SIZ; msg_len += sizeof(struct nfp_fl_rule_metadata); msg = nfp_flower_cmsg_init(mbuf, NFP_FLOWER_CMSG_TYPE_FLOW_DEL, msg_len); rte_memcpy(msg, flow->payload.meta, msg_len); cnt = nfp_flower_ctrl_vnic_xmit(app_fw_flower, mbuf); if (cnt == 0) { PMD_DRV_LOG(ERR, "Send cmsg through ctrl vnic failed."); rte_pktmbuf_free(mbuf); return -EIO; } return 0; } int nfp_flower_cmsg_flow_add(struct nfp_app_fw_flower *app_fw_flower, struct rte_flow *flow) { char *msg; uint16_t cnt; uint32_t msg_len; struct rte_mbuf *mbuf; struct nfp_fl_rule_metadata *nfp_flow_meta; mbuf = rte_pktmbuf_alloc(app_fw_flower->ctrl_pktmbuf_pool); if (mbuf == NULL) { PMD_DRV_LOG(DEBUG, "Failed to alloc mbuf for flow add."); return -ENOMEM; } /* copy the flow to mbuf */ nfp_flow_meta = flow->payload.meta; msg_len = (nfp_flow_meta->key_len + nfp_flow_meta->mask_len + nfp_flow_meta->act_len) << NFP_FL_LW_SIZ; msg_len += sizeof(struct nfp_fl_rule_metadata); msg = nfp_flower_cmsg_init(mbuf, NFP_FLOWER_CMSG_TYPE_FLOW_ADD, msg_len); rte_memcpy(msg, flow->payload.meta, msg_len); cnt = nfp_flower_ctrl_vnic_xmit(app_fw_flower, mbuf); if (cnt == 0) { PMD_DRV_LOG(ERR, "Send cmsg through ctrl vnic failed."); rte_pktmbuf_free(mbuf); return -EIO; } return 0; } int nfp_flower_cmsg_tun_neigh_v4_rule(struct nfp_app_fw_flower *app_fw_flower, struct nfp_flower_cmsg_tun_neigh_v4 *payload) { uint16_t cnt; size_t msg_len; struct rte_mbuf *mbuf; struct nfp_flower_cmsg_tun_neigh_v4 *msg; mbuf = rte_pktmbuf_alloc(app_fw_flower->ctrl_pktmbuf_pool); if (mbuf == NULL) { PMD_DRV_LOG(DEBUG, "Failed to alloc mbuf for v4 tun neigh"); return -ENOMEM; } msg_len = sizeof(struct nfp_flower_cmsg_tun_neigh_v4); if (!nfp_flower_support_decap_v2(app_fw_flower)) msg_len -= sizeof(struct nfp_flower_tun_neigh_ext); msg = nfp_flower_cmsg_init(mbuf, NFP_FLOWER_CMSG_TYPE_TUN_NEIGH, msg_len); memcpy(msg, payload, msg_len); cnt = nfp_flower_ctrl_vnic_xmit(app_fw_flower, mbuf); if (cnt == 0) { PMD_DRV_LOG(ERR, "Send cmsg through ctrl vnic failed."); rte_pktmbuf_free(mbuf); return -EIO; } return 0; } int nfp_flower_cmsg_tun_neigh_v6_rule(struct nfp_app_fw_flower *app_fw_flower, struct nfp_flower_cmsg_tun_neigh_v6 *payload) { uint16_t cnt; size_t msg_len; struct rte_mbuf *mbuf; struct nfp_flower_cmsg_tun_neigh_v6 *msg; mbuf = rte_pktmbuf_alloc(app_fw_flower->ctrl_pktmbuf_pool); if (mbuf == NULL) { PMD_DRV_LOG(DEBUG, "Failed to alloc mbuf for v6 tun neigh"); return -ENOMEM; } msg_len = sizeof(struct nfp_flower_cmsg_tun_neigh_v6); if (!nfp_flower_support_decap_v2(app_fw_flower)) msg_len -= sizeof(struct nfp_flower_tun_neigh_ext); msg = nfp_flower_cmsg_init(mbuf, NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6, msg_len); memcpy(msg, payload, msg_len); cnt = nfp_flower_ctrl_vnic_xmit(app_fw_flower, mbuf); if (cnt == 0) { PMD_DRV_LOG(ERR, "Send cmsg through ctrl vnic failed."); rte_pktmbuf_free(mbuf); return -EIO; } return 0; } int nfp_flower_cmsg_tun_off_v4(struct nfp_app_fw_flower *app_fw_flower) { uint16_t cnt; uint32_t count = 0; struct rte_mbuf *mbuf; struct nfp_flow_priv *priv; struct nfp_ipv4_addr_entry *entry; struct nfp_flower_cmsg_tun_ipv4_addr *msg; mbuf = rte_pktmbuf_alloc(app_fw_flower->ctrl_pktmbuf_pool); if (mbuf == NULL) { PMD_DRV_LOG(DEBUG, "Failed to alloc mbuf for v4 tun addr"); return -ENOMEM; } msg = nfp_flower_cmsg_init(mbuf, NFP_FLOWER_CMSG_TYPE_TUN_IPS, sizeof(*msg)); priv = app_fw_flower->flow_priv; rte_spinlock_lock(&priv->ipv4_off_lock); LIST_FOREACH(entry, &priv->ipv4_off_list, next) { if (count >= NFP_FL_IPV4_ADDRS_MAX) { rte_spinlock_unlock(&priv->ipv4_off_lock); PMD_DRV_LOG(ERR, "IPv4 offload exceeds limit."); return -ERANGE; } msg->ipv4_addr[count] = entry->ipv4_addr; count++; } msg->count = rte_cpu_to_be_32(count); rte_spinlock_unlock(&priv->ipv4_off_lock); cnt = nfp_flower_ctrl_vnic_xmit(app_fw_flower, mbuf); if (cnt == 0) { PMD_DRV_LOG(ERR, "Send cmsg through ctrl vnic failed."); rte_pktmbuf_free(mbuf); return -EIO; } return 0; } int nfp_flower_cmsg_tun_off_v6(struct nfp_app_fw_flower *app_fw_flower) { uint16_t cnt; uint32_t count = 0; struct rte_mbuf *mbuf; struct nfp_flow_priv *priv; struct nfp_ipv6_addr_entry *entry; struct nfp_flower_cmsg_tun_ipv6_addr *msg; mbuf = rte_pktmbuf_alloc(app_fw_flower->ctrl_pktmbuf_pool); if (mbuf == NULL) { PMD_DRV_LOG(DEBUG, "Failed to alloc mbuf for v6 tun addr"); return -ENOMEM; } msg = nfp_flower_cmsg_init(mbuf, NFP_FLOWER_CMSG_TYPE_TUN_IPS_V6, sizeof(*msg)); priv = app_fw_flower->flow_priv; rte_spinlock_lock(&priv->ipv6_off_lock); LIST_FOREACH(entry, &priv->ipv6_off_list, next) { if (count >= NFP_FL_IPV6_ADDRS_MAX) { rte_spinlock_unlock(&priv->ipv6_off_lock); PMD_DRV_LOG(ERR, "IPv6 offload exceeds limit."); return -ERANGE; } memcpy(&msg->ipv6_addr[count * 16], entry->ipv6_addr, 16UL); count++; } msg->count = rte_cpu_to_be_32(count); rte_spinlock_unlock(&priv->ipv6_off_lock); cnt = nfp_flower_ctrl_vnic_xmit(app_fw_flower, mbuf); if (cnt == 0) { PMD_DRV_LOG(ERR, "Send cmsg through ctrl vnic failed."); rte_pktmbuf_free(mbuf); return -EIO; } return 0; } int nfp_flower_cmsg_pre_tunnel_rule(struct nfp_app_fw_flower *app_fw_flower, struct nfp_fl_rule_metadata *nfp_flow_meta, uint16_t mac_idx, bool is_del) { uint16_t cnt; struct rte_mbuf *mbuf; struct nfp_flower_meta_tci *meta_tci; struct nfp_flower_cmsg_pre_tun_rule *msg; mbuf = rte_pktmbuf_alloc(app_fw_flower->ctrl_pktmbuf_pool); if (mbuf == NULL) { PMD_DRV_LOG(DEBUG, "Failed to alloc mbuf for pre tunnel rule"); return -ENOMEM; } msg = nfp_flower_cmsg_init(mbuf, NFP_FLOWER_CMSG_TYPE_PRE_TUN_RULE, sizeof(*msg)); meta_tci = (struct nfp_flower_meta_tci *)((char *)nfp_flow_meta + sizeof(struct nfp_fl_rule_metadata)); if (meta_tci->tci) msg->vlan_tci = meta_tci->tci; else msg->vlan_tci = 0xffff; if (is_del) msg->flags = rte_cpu_to_be_32(NFP_TUN_PRE_TUN_RULE_DEL); msg->port_idx = rte_cpu_to_be_16(mac_idx); msg->host_ctx_id = nfp_flow_meta->host_ctx_id; cnt = nfp_flower_ctrl_vnic_xmit(app_fw_flower, mbuf); if (cnt == 0) { PMD_DRV_LOG(ERR, "Send cmsg through ctrl vnic failed."); rte_pktmbuf_free(mbuf); return -EIO; } return 0; } int nfp_flower_cmsg_tun_mac_rule(struct nfp_app_fw_flower *app_fw_flower, struct rte_ether_addr *mac, uint16_t mac_idx, bool is_del) { uint16_t cnt; struct rte_mbuf *mbuf; struct nfp_flower_cmsg_tun_mac *msg; mbuf = rte_pktmbuf_alloc(app_fw_flower->ctrl_pktmbuf_pool); if (mbuf == NULL) { PMD_DRV_LOG(DEBUG, "Failed to alloc mbuf for tunnel mac"); return -ENOMEM; } msg = nfp_flower_cmsg_init(mbuf, NFP_FLOWER_CMSG_TYPE_TUN_MAC, sizeof(*msg)); msg->count = rte_cpu_to_be_16(1); msg->index = rte_cpu_to_be_16(mac_idx); rte_ether_addr_copy(mac, &msg->addr); if (is_del) msg->flags = rte_cpu_to_be_16(NFP_TUN_MAC_OFFLOAD_DEL_FLAG); cnt = nfp_flower_ctrl_vnic_xmit(app_fw_flower, mbuf); if (cnt == 0) { PMD_DRV_LOG(ERR, "Send cmsg through ctrl vnic failed."); rte_pktmbuf_free(mbuf); return -EIO; } return 0; }