/** * ksz9477_flower_parse_key_l2 - Parse Layer 2 key from flow rule and configure * ACL entries accordingly. * @dev: Pointer to the ksz_device. * @port: Port number. * @extack: Pointer to the netlink_ext_ack. * @rule: Pointer to the flow_rule. * @cookie: The cookie to associate with the entry. * @prio: The priority of the entry. * * This function parses the Layer 2 key from the flow rule and configures * the corresponding ACL entries. It checks for unsupported offloads and * available entries before proceeding with the configuration. * * Returns: 0 on success or a negative error code on failure.
*/ staticint ksz9477_flower_parse_key_l2(struct ksz_device *dev, int port, struct netlink_ext_ack *extack, struct flow_rule *rule, unsignedlong cookie, u32 prio)
{ struct ksz9477_acl_priv *acl = dev->ports[port].acl_priv; struct flow_match_eth_addrs ematch; struct ksz9477_acl_entries *acles; int required_entries;
u8 *src_mac = NULL;
u8 *dst_mac = NULL;
u16 ethtype = 0;
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) { struct flow_match_basic match;
flow_rule_match_basic(rule, &match);
if (match.key->n_proto) { if (match.mask->n_proto != ETHER_TYPE_FULL_MASK) {
NL_SET_ERR_MSG_MOD(extack, "ethernet type mask must be a full mask"); return -EINVAL;
}
ethtype = be16_to_cpu(match.key->n_proto);
}
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
flow_rule_match_eth_addrs(rule, &ematch);
if (!is_zero_ether_addr(ematch.key->src)) { if (!is_broadcast_ether_addr(ematch.mask->src)) goto not_full_mask_err;
src_mac = ematch.key->src;
}
if (!is_zero_ether_addr(ematch.key->dst)) { if (!is_broadcast_ether_addr(ematch.mask->dst)) goto not_full_mask_err;
dst_mac = ematch.key->dst;
}
}
acles = &acl->acles; /* ACL supports only one MAC per entry */
required_entries = src_mac && dst_mac ? 2 : 1;
/* Check if there are enough available entries */ if (acles->entries_count + required_entries > KSZ9477_ACL_MAX_ENTRIES) {
NL_SET_ERR_MSG_MOD(extack, "ACL entry limit reached"); return -EOPNOTSUPP;
}
not_full_mask_err:
NL_SET_ERR_MSG_MOD(extack, "MAC address mask must be a full mask"); return -EOPNOTSUPP;
}
/** * ksz9477_flower_parse_key - Parse flow rule keys for a specified port on a * ksz_device. * @dev: The ksz_device instance. * @port: The port number to parse the flow rule keys for. * @extack: The netlink extended ACK for reporting errors. * @rule: The flow_rule to parse. * @cookie: The cookie to associate with the entry. * @prio: The priority of the entry. * * This function checks if the used keys in the flow rule are supported by * the device and parses the L2 keys if they match. If unsupported keys are * used, an error message is set in the extended ACK. * * Returns: 0 on success or a negative error code on failure.
*/ staticint ksz9477_flower_parse_key(struct ksz_device *dev, int port, struct netlink_ext_ack *extack, struct flow_rule *rule, unsignedlong cookie, u32 prio)
{ struct flow_dissector *dissector = rule->match.dissector; int ret;
if (flow_rule_match_has_control_flags(rule, extack)) return -EOPNOTSUPP;
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC) ||
flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
ret = ksz9477_flower_parse_key_l2(dev, port, extack, rule,
cookie, prio); if (ret) return ret;
}
return 0;
}
/** * ksz9477_flower_parse_action - Parse flow rule actions for a specified port * on a ksz_device. * @dev: The ksz_device instance. * @port: The port number to parse the flow rule actions for. * @extack: The netlink extended ACK for reporting errors. * @cls: The flow_cls_offload instance containing the flow rule. * @entry_idx: The index of the ACL entry to store the action. * * This function checks if the actions in the flow rule are supported by * the device. Currently, only actions that change priorities are supported. * If unsupported actions are encountered, an error message is set in the * extended ACK. * * Returns: 0 on success or a negative error code on failure.
*/ staticint ksz9477_flower_parse_action(struct ksz_device *dev, int port, struct netlink_ext_ack *extack, struct flow_cls_offload *cls, int entry_idx)
{ struct flow_rule *rule = flow_cls_offload_flow_rule(cls); struct ksz9477_acl_priv *acl = dev->ports[port].acl_priv; conststruct flow_action_entry *act; struct ksz9477_acl_entry *entry; bool prio_force = false;
u8 prio_val = 0; int i;
if (TC_H_MIN(cls->classid)) {
NL_SET_ERR_MSG_MOD(extack, "hw_tc is not supported. Use: action skbedit prio"); return -EOPNOTSUPP;
}
flow_action_for_each(i, act, &rule->action) { switch (act->id) { case FLOW_ACTION_PRIORITY: if (act->priority > KSZ9477_MAX_TC) {
NL_SET_ERR_MSG_MOD(extack, "Priority value is too high"); return -EOPNOTSUPP;
}
prio_force = true;
prio_val = act->priority; break; default:
NL_SET_ERR_MSG_MOD(extack, "action not supported"); return -EOPNOTSUPP;
}
}
/* pick entry to store action */
entry = &acl->acles.entries[entry_idx];
/** * ksz9477_cls_flower_add - Add a flow classification rule for a specified port * on a ksz_device. * @ds: The DSA switch instance. * @port: The port number to add the flow classification rule to. * @cls: The flow_cls_offload instance containing the flow rule. * @ingress: A flag indicating if the rule is applied on the ingress path. * * This function adds a flow classification rule for a specified port on a * ksz_device. It checks if the ACL offloading is supported and parses the flow * keys and actions. If the ACL is not supported, it returns an error. If there * are unprocessed entries, it parses the action for the rule. * * Returns: 0 on success or a negative error code on failure.
*/ int ksz9477_cls_flower_add(struct dsa_switch *ds, int port, struct flow_cls_offload *cls, bool ingress)
{ struct flow_rule *rule = flow_cls_offload_flow_rule(cls); struct netlink_ext_ack *extack = cls->common.extack; struct ksz_device *dev = ds->priv; struct ksz9477_acl_priv *acl; int action_entry_idx; int ret;
acl = dev->ports[port].acl_priv;
if (!acl) {
NL_SET_ERR_MSG_MOD(extack, "ACL offloading is not supported"); return -EOPNOTSUPP;
}
/* A complex rule set can take multiple entries. Use first entry * to store the action.
*/
action_entry_idx = acl->acles.entries_count;
ret = ksz9477_flower_parse_key(dev, port, extack, rule, cls->cookie,
cls->common.prio); if (ret) return ret;
ret = ksz9477_flower_parse_action(dev, port, extack, cls,
action_entry_idx); if (ret) return ret;
ret = ksz9477_sort_acl_entries(dev, port); if (ret) return ret;
return ksz9477_acl_write_list(dev, port);
}
/** * ksz9477_cls_flower_del - Remove a flow classification rule for a specified * port on a ksz_device. * @ds: The DSA switch instance. * @port: The port number to remove the flow classification rule from. * @cls: The flow_cls_offload instance containing the flow rule. * @ingress: A flag indicating if the rule is applied on the ingress path. * * This function removes a flow classification rule for a specified port on a * ksz_device. It checks if the ACL is initialized, and if not, returns an * error. If the ACL is initialized, it removes entries with the specified * cookie and rewrites the ACL list. * * Returns: 0 on success or a negative error code on failure.
*/ int ksz9477_cls_flower_del(struct dsa_switch *ds, int port, struct flow_cls_offload *cls, bool ingress)
{ unsignedlong cookie = cls->cookie; struct ksz_device *dev = ds->priv; struct ksz9477_acl_priv *acl;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.