Line data Source code
1 : /* SPDX-License-Identifier: BSD-2-Clause 2 : * Copyright(c) HCL TECHNOLOGIES LTD 3 : * Submitted on behalf of a third-party: Intel Corporation, a 4 : * Delaware corporation, having its principal place of business 5 : * at 2200 Mission College Boulevard, 6 : * Santa Clara, California 95052, USA 7 : */ 8 : 9 : #include "vr_dpdk_n3k_offloads.h" 10 : #include "vr_dpdk_n3k_missing_mirror.h" 11 : #include "vr_dpdk_n3k_interface.h" 12 : #include "vr_dpdk_n3k_flow.h" 13 : 14 : #include <rte_log.h> 15 : #include <rte_malloc.h> 16 : 17 : #include "vr_dpdk.h" 18 : #include "vr_interface.h" 19 : 20 : struct interface_meta { 21 : bool exists; 22 : uint8_t mirror_id; 23 : }; 24 : 25 : /* Note: This array does not need to be protected by any lock, as it's accessed 26 : * only from add/del callbacks, which vrouter calls only from only one thread 27 : * (dpdk_lcore_netlink_loop) */ 28 : static struct interface_meta *interfaces; 29 : 30 : int 31 0 : vr_dpdk_n3k_offload_interface_init(uint16_t count) 32 : { 33 0 : interfaces = rte_zmalloc("n3k_offload_vif", count * sizeof(*interfaces), 0); 34 0 : if (interfaces == NULL) 35 0 : return -ENOMEM; 36 : 37 0 : return 0; 38 : } 39 : 40 : void 41 0 : vr_dpdk_n3k_offload_interface_exit(void) 42 : { 43 0 : rte_free(interfaces); 44 0 : interfaces = NULL; 45 0 : } 46 : 47 62 : static bool is_vif_supported(const struct vr_interface *vif) { 48 : /* TODO(n3k): Handle multiple routers */ 49 62 : if (vif->vif_rid != 0) 50 0 : return false; 51 : 52 62 : if (!vif_is_fabric(vif) && !vif_is_virtual(vif)) 53 0 : return false; 54 : 55 62 : if (vif->vif_os == NULL) { 56 0 : RTE_LOG(ERR, VROUTER, 57 : "Failed to translate vr_interface (idx=%hu) into port_id, vif_os is NULL.\n", 58 : vif->vif_idx); 59 0 : return false; 60 : } 61 62 : return true; 62 : } 63 : 64 : const struct vr_interface * 65 62 : vr_dpdk_n3k_offload_interface_get(uint16_t id,struct vr_interface **used_as_virtual) 66 : { 67 : /* Using intermediate variable to avoid changing used_as_virtual on fail */ 68 62 : struct vr_interface *virtual_vif = NULL; 69 : 70 : /* Note: Using `__vrouter_get_interface` instead of 71 : * `vrouter_get_interface`, as we don't need nor want to touch the 72 : * refcount. See the comment on `vr_dpdk_n3k_offload_nexthop_get */ 73 62 : struct vr_interface *vif = __vrouter_get_interface(vrouter_get(0), id); 74 : 75 62 : if (vif == NULL) 76 0 : return NULL; 77 : 78 : /* For virtual VLAN, use parent interface */ 79 62 : if (vif_is_vlan(vif) && (vif->vif_parent != NULL)) { 80 0 : virtual_vif = vif; 81 0 : vif = __vrouter_get_interface(vrouter_get(0), vif->vif_parent->vif_idx); 82 : } 83 : 84 62 : if (vif == NULL || !is_vif_supported(vif)) 85 0 : return NULL; 86 : 87 62 : if (used_as_virtual != NULL) 88 56 : *used_as_virtual = virtual_vif; 89 : 90 62 : return vif; 91 : } 92 : 93 : int 94 0 : vr_dpdk_n3k_offload_interface_add(struct vr_interface *vif) 95 : { 96 0 : int ret = 0; 97 0 : unsigned short id = vif->vif_idx; 98 : 99 0 : bool mirror_changed = interfaces[id].exists && interfaces[id].mirror_id != vif->vif_mirror_id; 100 : 101 0 : interfaces[id] = (struct interface_meta) { 102 : .exists = true, 103 0 : .mirror_id = vif->vif_mirror_id, 104 : }; 105 : 106 0 : if (!is_vif_supported(vif)) { 107 0 : return 0; 108 : } 109 : 110 0 : vr_dpdk_n3k_offload_lock(); 111 : 112 0 : if (mirror_changed) { 113 0 : ret = vr_dpdk_n3k_offload_flow_vif_update_unlocked(vif); 114 0 : if (ret) { 115 0 : RTE_LOG(ERR, VROUTER, "%s(): vif's flows update failed: %d\n", 116 : __func__, ret); 117 0 : goto out; 118 : } 119 : } 120 : 121 0 : vr_dpdk_n3k_offload_missing_vif_flows_unlocked(vif->vif_idx); 122 : 123 0 : out: 124 0 : vr_dpdk_n3k_offload_unlock(); 125 : 126 0 : return ret; 127 : } 128 : 129 : int 130 0 : vr_dpdk_n3k_offload_interface_del(struct vr_interface *vif) 131 : { 132 0 : interfaces[vif->vif_idx].exists = false; 133 0 : return 0; 134 : }