--- zzzz-none-000/linux-5.15.111/net/openvswitch/actions.c 2023-05-11 14:00:40.000000000 +0000 +++ puma7-atom-6670-761/linux-5.15.111/net/openvswitch/actions.c 2024-02-07 10:23:30.000000000 +0000 @@ -3,6 +3,16 @@ * Copyright (c) 2007-2017 Nicira, Inc. */ +/* + * Includes Inango Systems Ltd’s changes/modifications dated: 2021. + * Changed/modified portions - Copyright (c) 2021 , Inango Systems Ltd. + */ + +/* + Includes MaxLinear's changes dated: 2021, 2022, 2023. + Changed portions - Copyright 2021-2023 MaxLinear, Inc. +*/ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include @@ -25,6 +35,7 @@ #include #include +#include "am_pp.h" #include "datapath.h" #include "flow.h" #include "conntrack.h" @@ -154,11 +165,14 @@ struct sw_flow_key *key, u32 recirc_id, const struct nlattr *actions, int len, - bool last, bool clone_flow_key); + bool last, bool clone_flow_key, + struct sw_flow *flow/* + const struct sw_flow_id *ufid*/); static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, - struct sw_flow_key *key, - const struct nlattr *attr, int len); + struct sw_flow_key *key, + const struct nlattr *attr, int len, + struct sw_flow *flow); static int push_mpls(struct sk_buff *skb, struct sw_flow_key *key, __be32 mpls_lse, __be16 mpls_ethertype, __u16 mac_len) @@ -1000,14 +1014,15 @@ static int dec_ttl_exception_handler(struct datapath *dp, struct sk_buff *skb, struct sw_flow_key *key, - const struct nlattr *attr) + const struct nlattr *attr, + struct sw_flow *flow) { /* The first attribute is always 'OVS_DEC_TTL_ATTR_ACTION'. */ struct nlattr *actions = nla_data(attr); if (nla_len(actions)) return clone_execute(dp, skb, key, 0, nla_data(actions), - nla_len(actions), true, false); + nla_len(actions), true, false, flow); consume_skb(skb); return 0; @@ -1019,7 +1034,7 @@ */ static int sample(struct datapath *dp, struct sk_buff *skb, struct sw_flow_key *key, const struct nlattr *attr, - bool last) + bool last, struct sw_flow *flow/*const structsw_flow_id *ufid*/) { struct nlattr *actions; struct nlattr *sample_arg; @@ -1041,7 +1056,7 @@ clone_flow_key = !arg->exec; return clone_execute(dp, skb, key, 0, actions, rem, last, - clone_flow_key); + clone_flow_key, flow/*ufid*/); } /* When 'last' is true, clone() should always consume the 'skb'. @@ -1050,7 +1065,7 @@ */ static int clone(struct datapath *dp, struct sk_buff *skb, struct sw_flow_key *key, const struct nlattr *attr, - bool last) + bool last, struct sw_flow *flow/*const structsw_flow_id *ufid*/) { struct nlattr *actions; struct nlattr *clone_arg; @@ -1063,7 +1078,7 @@ actions = nla_next(clone_arg, &rem); return clone_execute(dp, skb, key, 0, actions, rem, last, - !dont_clone_flow_key); + !dont_clone_flow_key, flow/*ufid*/); } static void execute_hash(struct sk_buff *skb, struct sw_flow_key *key, @@ -1178,7 +1193,8 @@ static int execute_recirc(struct datapath *dp, struct sk_buff *skb, struct sw_flow_key *key, - const struct nlattr *a, bool last) + const struct nlattr *a, bool last, + struct sw_flow *flow/*const struct sw_flow_id *ufid*/) { u32 recirc_id; @@ -1192,12 +1208,15 @@ BUG_ON(!is_flow_key_valid(key)); recirc_id = nla_get_u32(a); - return clone_execute(dp, skb, key, recirc_id, NULL, 0, last, true); + return clone_execute(dp, skb, key, recirc_id, NULL, 0, last, true, flow/*ufid*/); } static int execute_check_pkt_len(struct datapath *dp, struct sk_buff *skb, struct sw_flow_key *key, - const struct nlattr *attr, bool last) + const struct nlattr *attr, + bool last, + struct sw_flow *flow/* + const struct sw_flow_id *ufid*/) { struct ovs_skb_cb *ovs_cb = OVS_CB(skb); const struct nlattr *actions, *cpl_arg; @@ -1231,7 +1250,7 @@ } return clone_execute(dp, skb, key, 0, nla_data(actions), - nla_len(actions), last, clone_flow_key); + nla_len(actions), last, clone_flow_key, flow/*ufid*/); } static int execute_dec_ttl(struct sk_buff *skb, struct sw_flow_key *key) @@ -1273,13 +1292,83 @@ return 0; } +static bool is_flood_flow(const struct sw_flow_key *key, + const struct nlattr *attr, + int len, struct sw_flow *flow) +{ + if (flow->flow_type == BROADCAST_FLOW_TYPE || flow->flow_type == UNKNOWN_UNICAST_FLOW_TYPE) + return true; + else if (flow->flow_type != UNKNOWN_FLOW_TYPE) + return false; + + if (!is_multicast_ether_addr(key->eth.dst) + && is_broadcast_ether_addr(key->eth.dst)) { + return true; + } + + return false; +} + +static bool should_skip(const struct sw_flow_key *key, + const struct nlattr *attr, int len, + struct sw_flow *flow) +{ + const struct nlattr *a; + int rem; + + if (flow->acl_state != ACCELERATED) + return true; + + for (a = attr, rem = len; rem > 0; a = nla_next(a, &rem)) + { + switch (nla_type(a)) + { + case OVS_ACTION_ATTR_USERSPACE: + return true; + break; + case OVS_ACTION_ATTR_SKIP_ACC: + { + struct ovs_flow_stats stats; + __be16 tcp_flags; + unsigned long used; + struct ovs_action_skip_acc * skip_acc; + skip_acc = nla_data(a); + ovs_flow_stats_get(flow, &stats, &used, &tcp_flags); + if (stats.n_packets < skip_acc->number_of_packets-1) + { + return true; + } + break; + } + } + } + + return false; +} /* Execute a list of actions against 'skb'. */ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, struct sw_flow_key *key, - const struct nlattr *attr, int len) + const struct nlattr *attr, int len, + struct sw_flow *flow + /*const struct sw_flow_id *ufid*/) { const struct nlattr *a; int rem; + struct vport *prev = NULL; + + // TODO: Set correct action instead of PP_AM_SET_OUTPUT + am_skb_preprocessing(PP_AM_SET_OUTPUT, flow/*ufid*/, skb); + + if (should_skip(key, attr, len, flow)) { + am_skb_postprocessing(PP_AM_SET_SKIP, flow/*ufid*/, skb); + } + if (is_flood_flow(key, attr, len, flow)) { + am_skb_postprocessing(PP_AM_SET_FLOOD, flow/*ufid*/, skb); + } + + if (is_multicast_ether_addr(eth_hdr(skb)->h_dest) && !is_broadcast_ether_addr(eth_hdr(skb)->h_dest)) { + am_skb_postprocessing(PP_AM_SET_MCAST_FLOOD, flow/*ufid*/, skb); + } for (a = attr, rem = len; rem > 0; a = nla_next(a, &rem)) { @@ -1292,6 +1381,7 @@ case OVS_ACTION_ATTR_OUTPUT: { int port = nla_get_u32(a); struct sk_buff *clone; + am_skb_postprocessing(PP_AM_SET_OUTPUT, flow/*ufid*/, skb); /* Every output action needs a separate clone * of 'skb', In case the output action is the @@ -1311,6 +1401,72 @@ break; } + case OVS_ACTION_ATTR_MULTICAST_OUTPUT: { + struct ovs_action_mcast_output *mcast_output = nla_data(a); + int port = mcast_output->out_port; + struct sk_buff *clone; + struct vport *vport; + struct pp_am_mcast_port_output mcast_port_output; + + am_skb_postprocessing(PP_AM_SET_OUTPUT, flow/*ufid*/, skb); + vport = ovs_vport_rcu(dp, port); + if (likely(vport)) { +#ifdef CONFIG_OPENVSWITCH_BRCOMPAT + if (vport->type != OVS_VPORT_TYPE_INTERNAL) { +#else + if (vport->ops->type != OVS_VPORT_TYPE_INTERNAL) { +#endif + mcast_port_output.ifindex = vport->dev->ifindex; + memcpy(mcast_port_output.host_mac, mcast_output->host_mac, sizeof(mcast_port_output.host_mac)); + + am_skb_postprocessing_ext(PP_AM_SET_MCAST_PORT_OUTPUT, flow, skb, &mcast_port_output); + } + } + + /* Every output action needs a separate clone + * of 'skb', In case the output action is the + * last action, cloning can be avoided. + */ + if (nla_is_last(a, rem)) { + if (prev != vport) + do_output(dp, skb, port, key); + else + kfree_skb(skb); + /* 'skb' has been used for output. + */ + return 0; + } + if (prev == vport) + break; + + prev = vport; + clone = skb_clone(skb, GFP_ATOMIC); + if (clone) + do_output(dp, clone, port, key); + OVS_CB(skb)->cutlen = 0; + break; + } + + case OVS_ACTION_ATTR_SET_OF_MARK1: { +#ifdef CONFIG_TI_PACKET_PROCESSOR + struct ovs_action_set_of_mark *of_mark = nla_data(a); + SKB_GET_PP_INFO_P(skb)->pp_session.of_mark1 = + (SKB_GET_PP_INFO_P(skb)->pp_session.of_mark1 & ~of_mark->mask) | + (of_mark->value & of_mark->mask); +#endif + break; + } + + case OVS_ACTION_ATTR_SET_OF_MARK2: { +#ifdef CONFIG_TI_PACKET_PROCESSOR + struct ovs_action_set_of_mark *of_mark = nla_data(a); + SKB_GET_PP_INFO_P(skb)->pp_session.of_mark2 = + (SKB_GET_PP_INFO_P(skb)->pp_session.of_mark2 & ~of_mark->mask) | + (of_mark->value & of_mark->mask); +#endif + break; + } + case OVS_ACTION_ATTR_TRUNC: { struct ovs_action_trunc *trunc = nla_data(a); @@ -1362,7 +1518,7 @@ case OVS_ACTION_ATTR_RECIRC: { bool last = nla_is_last(a, rem); - err = execute_recirc(dp, skb, key, a, last); + err = execute_recirc(dp, skb, key, a, last, flow/*ufid*/); if (last) { /* If this is the last action, the skb has * been consumed or freed. @@ -1385,7 +1541,7 @@ case OVS_ACTION_ATTR_SAMPLE: { bool last = nla_is_last(a, rem); - err = sample(dp, skb, key, a, last); + err = sample(dp, skb, key, a, last, flow/*ufid*/); if (last) return err; @@ -1445,7 +1601,7 @@ case OVS_ACTION_ATTR_CLONE: { bool last = nla_is_last(a, rem); - err = clone(dp, skb, key, a, last); + err = clone(dp, skb, key, a, last, flow/*ufid*/); if (last) return err; @@ -1455,7 +1611,7 @@ case OVS_ACTION_ATTR_CHECK_PKT_LEN: { bool last = nla_is_last(a, rem); - err = execute_check_pkt_len(dp, skb, key, a, last); + err = execute_check_pkt_len(dp, skb, key, a, last, flow/*ufid*/); if (last) return err; @@ -1466,7 +1622,7 @@ err = execute_dec_ttl(skb, key); if (err == -EHOSTUNREACH) return dec_ttl_exception_handler(dp, skb, - key, a); + key, a, flow); break; } @@ -1475,6 +1631,7 @@ return err; } } + am_skb_postprocessing(PP_AM_SET_DROP, flow/*ufid*/, skb); consume_skb(skb); return 0; @@ -1489,7 +1646,8 @@ static int clone_execute(struct datapath *dp, struct sk_buff *skb, struct sw_flow_key *key, u32 recirc_id, const struct nlattr *actions, int len, - bool last, bool clone_flow_key) + bool last, bool clone_flow_key, + struct sw_flow *flow) { struct deferred_action *da; struct sw_flow_key *clone; @@ -1516,7 +1674,7 @@ __this_cpu_inc(exec_actions_level); err = do_execute_actions(dp, skb, clone, - actions, len); + actions, len, flow/*ufid*/); if (clone_flow_key) __this_cpu_dec(exec_actions_level); @@ -1553,7 +1711,7 @@ return 0; } -static void process_deferred_actions(struct datapath *dp) +static void process_deferred_actions(struct datapath *dp, struct sw_flow *flow/*const struct sw_flow_id *ufid*/) { struct action_fifo *fifo = this_cpu_ptr(action_fifos); @@ -1570,7 +1728,7 @@ int actions_len = da->actions_len; if (actions) - do_execute_actions(dp, skb, key, actions, actions_len); + do_execute_actions(dp, skb, key, actions, actions_len, flow/*ufid*/); else ovs_dp_process_packet(skb, key); } while (!action_fifo_is_empty(fifo)); @@ -1582,7 +1740,9 @@ /* Execute a list of actions against 'skb'. */ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb, const struct sw_flow_actions *acts, - struct sw_flow_key *key) + struct sw_flow *flow/*, + struct sw_flow_key *key, + const struct sw_flow_id *ufid*/) { int err, level; @@ -1596,11 +1756,11 @@ } OVS_CB(skb)->acts_origlen = acts->orig_len; - err = do_execute_actions(dp, skb, key, - acts->actions, acts->actions_len); + err = do_execute_actions(dp, skb, &flow->key,/*key,*/ + acts->actions, acts->actions_len, flow/*ufid*/); if (level == 1) - process_deferred_actions(dp); + process_deferred_actions(dp, flow/*ufid*/); out: __this_cpu_dec(exec_actions_level);