/* 'skb' is a frame meant for another host. * 'port' is the outgoing interface * * Substitute the target (dest) MAC address if necessary, so the it matches the * recipient interface MAC address, regardless of whether that is the * recipient's A or B interface. * This is needed to keep the packets flowing through switches that learn on * which "side" the different interfaces are. */ void hsr_addr_subst_dest(struct hsr_node *node_src, struct sk_buff *skb, struct hsr_port *port) { struct hsr_node *node_dst; if (!skb_mac_header_was_set(skb)) { WARN_ONCE(1, "%s: Mac header not set\n", __func__); return; } if (!is_unicast_ether_addr(eth_hdr(skb)->h_dest)) return; node_dst = find_node_by_AddrA(&port->hsr->node_db, eth_hdr(skb)->h_dest); if (!node_dst) { WARN_ONCE(1, "%s: Unknown node\n", __func__); return; } if (port->type != node_dst->AddrB_port) return; ether_addr_co
/** * Convert Ethernet item to EFX filter specification. * * @param item[in] * Item specification. Only source and destination addresses and * Ethernet type fields are supported. In addition to full and * empty masks of destination address, individual/group mask is * also supported. If the mask is NULL, default mask will be used. * Ranging is not supported. * @param efx_spec[in, out] * EFX filter specification to update. * @param[out] error * Perform verbose error reporting if not NULL. */ static int sfc_flow_parse_eth(const struct rte_flow_item *item, efx_filter_spec_t *efx_spec, struct rte_flow_error *error) { int rc; const struct rte_flow_item_eth *spec = NULL; const struct rte_flow_item_eth *mask = NULL; const struct rte_flow_item_eth supp_mask = { .dst.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, .src.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, .type = 0xffff, }; const uint8_t ig_mask[EFX_MAC_ADDR_LEN] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }; rc = sfc_flow_parse_init(item, (const void **)&spec, (const void **)&mask, &supp_mask, &rte_flow_item_eth_mask, sizeof(struct rte_flow_item_eth), error); if (rc != 0) return rc; /* If "spec" is not set, could be any Ethernet */ if (spec == NULL) return 0; if (is_same_ether_addr(&mask->dst, &supp_mask.dst)) { efx_spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC; rte_memcpy(efx_spec->efs_loc_mac, spec->dst.addr_bytes, EFX_MAC_ADDR_LEN); } else if (memcmp(mask->dst.addr_bytes, ig_mask, EFX_MAC_ADDR_LEN) == 0) { if (is_unicast_ether_addr(&spec->dst)) efx_spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_UCAST_DST; else efx_spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_MCAST_DST; } else if (!is_zero_ether_addr(&mask->dst)) { goto fail_bad_mask; } if (is_same_ether_addr(&mask->src, &supp_mask.src)) { efx_spec->efs_match_flags |= EFX_FILTER_MATCH_REM_MAC; rte_memcpy(efx_spec->efs_rem_mac, spec->src.addr_bytes, EFX_MAC_ADDR_LEN); } else if (!is_zero_ether_addr(&mask->src)) { goto fail_bad_mask; } /* * Ether type is in big-endian byte order in item and * in little-endian in efx_spec, so byte swap is used */ if (mask->type == supp_mask.type) { efx_spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE; efx_spec->efs_ether_type = rte_bswap16(spec->type); } else if (mask->type != 0) { goto fail_bad_mask; } return 0; fail_bad_mask: rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item, "Bad mask in the ETH pattern item"); return -rte_errno; } /** * Convert VLAN item to EFX filter specification. * * @param item[in] * Item specification. Only VID field is supported. * The mask can not be NULL. Ranging is not supported. * @param efx_spec[in, out] * EFX filter specification to update. * @param[out] error * Perform verbose error reporting if not NULL. */ static int sfc_flow_parse_vlan(const struct rte_flow_item *item, efx_filter_spec_t *efx_spec, struct rte_flow_error *error) { int rc; uint16_t vid; const struct rte_flow_item_vlan *spec = NULL; const struct rte_flow_item_vlan *mask = NULL; const struct rte_flow_item_vlan supp_mask = { .tci = rte_cpu_to_be_16(ETH_VLAN_ID_MAX), }; rc = sfc_flow_parse_init(item, (const void **)&spec, (const void **)&mask, &supp_mask, NULL, sizeof(struct rte_flow_item_vlan), error); if (rc != 0) return rc; /* * VID is in big-endian byte order in item and * in little-endian in efx_spec, so byte swap is used. * If two VLAN items are included, the first matches * the outer tag and the next matches the inner tag. */ if (mask->tci == supp_mask.tci) { /* Apply mask to keep VID only */ vid = rte_bswap16(spec->tci & mask->tci); if (!(efx_spec->efs_match_flags & EFX_FILTER_MATCH_OUTER_VID)) { efx_spec->efs_match_flags |= EFX_FILTER_MATCH_OUTER_VID; efx_spec->efs_outer_vid = vid; } else if (!(efx_spec->efs_match_flags & EFX_FILTER_MATCH_INNER_VID)) { efx_spec->efs_match_flags |= EFX_FILTER_MATCH_INNER_VID; efx_spec->efs_inner_vid = vid; } else { rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item, "More than two VLAN items"); return -rte_errno; } } else { rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item, "VLAN ID in TCI match is required"); return -rte_errno; } return 0; }