Hi Taimur

The attached patch is what you need. I hope it works for you.

- Volkan
________________________________________
From: ovs-discuss-boun...@openvswitch.org [ovs-discuss-boun...@openvswitch.org] 
on behalf of Taimur Hafeez [taimurhafee...@gmail.com]
Sent: Wednesday, March 21, 2018 11:58 AM
To: ovs-discuss@openvswitch.org
Subject: [ovs-discuss] Setting TCP rwnd value in Open vSwitch

Dear All,

I want to modify value of receiver window field(used for flow control) in the 
TCP header using OpenFlow rule at Open vSwitch. To make it clear what I am 
trying to do, lets illustrate this in the following way,

In_port=1, match src_ip=10.0.0.1, action:set_tcp_rwnd=10, out_port=2

Specifications:

Controller ryu
OpenFlow 1.3
OVS 2.5.2

Help/Clue would be highly appreciated, If anyone has done similar work. Thanks 
in advance!


Best regards,
--------------------
Taimur Hafeez
NUST School of Electrical Engineering and Computer Science (SEECS), Islamabad, 
Pakistan.
diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
index 12260d8..dd84b04 100644
--- a/datapath/linux/compat/include/linux/openvswitch.h
+++ b/datapath/linux/compat/include/linux/openvswitch.h
@@ -352,6 +352,8 @@ enum ovs_key_attr {
 	OVS_KEY_ATTR_MPLS,      /* array of struct ovs_key_mpls.
 				 * The implementation may restrict
 				 * the accepted length of the array. */
+	OVS_KEY_ATTR_REDUCE_RWND,
+	OVS_KEY_ATTR_SET_RWND,
 	OVS_KEY_ATTR_CT_STATE,	/* u32 bitmask of OVS_CS_F_* */
 	OVS_KEY_ATTR_CT_ZONE,	/* u16 connection tracking zone. */
 	OVS_KEY_ATTR_CT_MARK,	/* u32 connection tracking mark */
@@ -433,6 +435,14 @@ struct ovs_key_ipv6 {
 	__u8   ipv6_frag;	/* One of OVS_FRAG_TYPE_*. */
 };
 
+struct ovs_key_reduce_rwnd {
+	uint8_t rate;
+};
+
+struct ovs_key_set_rwnd {
+	ovs_be16 rwnd;
+};
+
 struct ovs_key_tcp {
 	__be16 tcp_src;
 	__be16 tcp_dst;
diff --git a/include/openvswitch/flow.h b/include/openvswitch/flow.h
index df80dfe..64da205 100644
--- a/include/openvswitch/flow.h
+++ b/include/openvswitch/flow.h
@@ -120,7 +120,9 @@ struct flow {
     struct eth_addr arp_sha;    /* ARP/ND source hardware address. */
     struct eth_addr arp_tha;    /* ARP/ND target hardware address. */
     ovs_be16 tcp_flags;         /* TCP flags. With L3 to avoid matching L4. */
-    ovs_be16 pad3;              /* Pad to 64 bits. */
+    ovs_be16 rwnd;
+    uint8_t rate;
+    uint8_t pad3[7];              /* Pad to 64 bits. */
 
     /* L4 (64-bit aligned) */
     ovs_be16 tp_src;            /* TCP/UDP/SCTP source port/ICMP type. */
@@ -135,7 +137,7 @@ BUILD_ASSERT_DECL(sizeof(struct flow_tnl) % sizeof(uint64_t) == 0);
 
 /* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
 BUILD_ASSERT_DECL(offsetof(struct flow, igmp_group_ip4) + sizeof(uint32_t)
-                  == sizeof(struct flow_tnl) + 248
+                  == sizeof(struct flow_tnl) + 256
                   && FLOW_WC_SEQ == 36);
 
 /* Incremental points at which flow classification may be performed in
diff --git a/include/openvswitch/ofp-actions.h b/include/openvswitch/ofp-actions.h
index 74e9dcc..a7512e5 100644
--- a/include/openvswitch/ofp-actions.h
+++ b/include/openvswitch/ofp-actions.h
@@ -86,6 +86,8 @@
     OFPACT(DEC_MPLS_TTL,    ofpact_null,        ofpact, "dec_mpls_ttl") \
     OFPACT(PUSH_MPLS,       ofpact_push_mpls,   ofpact, "push_mpls")    \
     OFPACT(POP_MPLS,        ofpact_pop_mpls,    ofpact, "pop_mpls")     \
+    OFPACT(REDUCE_RWND,     ofpact_reduce_rwnd, ofpact, "reduce_rwnd")  \
+    OFPACT(SET_RWND,        ofpact_set_rwnd,    ofpact, "set_rwnd")     \
                                                                         \
     /* Metadata. */                                                     \
     OFPACT(SET_TUNNEL,      ofpact_tunnel,      ofpact, "set_tunnel")   \
@@ -426,6 +428,16 @@ struct ofpact_ip_ttl {
     uint8_t ttl;
 };
 
+struct ofpact_reduce_rwnd {
+    struct ofpact ofpact;
+    uint8_t rate;
+};
+
+struct ofpact_set_rwnd {
+    struct ofpact ofpact;
+    uint16_t rwnd;
+};
+
 /* OFPACT_SET_L4_SRC_PORT, OFPACT_SET_L4_DST_PORT.
  *
  * Used for OFPAT10_SET_TP_SRC, OFPAT10_SET_TP_DST. */
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index 65a6fcd..b052f1c 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -271,6 +271,21 @@ odp_execute_set_action(struct dp_packet *packet, const struct nlattr *a)
         }
         break;
 
+    case OVS_KEY_ATTR_REDUCE_RWND:
+        if (OVS_LIKELY(dp_packet_get_tcp_payload(packet))) {
+            const uint8_t rate = nl_attr_get_u8(a);
+            packet_reduce_rwnd(packet, rate);
+        }
+
+        break;
+    case OVS_KEY_ATTR_SET_RWND:
+        if (OVS_LIKELY(dp_packet_get_tcp_payload(packet))) {
+            const uint16_t rwnd = nl_attr_get_u16(a);
+            packet_set_rwnd(packet, rwnd);
+        }
+
+        break;
+
     case OVS_KEY_ATTR_UDP:
         if (OVS_LIKELY(dp_packet_get_udp_payload(packet))) {
             const struct ovs_key_udp *udp_key
@@ -422,6 +437,8 @@ odp_execute_masked_set_action(struct dp_packet *packet,
             | (md->recirc_id & ~*get_mask(a, uint32_t));
         break;
 
+    case OVS_KEY_ATTR_REDUCE_RWND:
+    case OVS_KEY_ATTR_SET_RWND:
     case OVS_KEY_ATTR_TUNNEL:    /* Masked data not supported for tunnel. */
     case OVS_KEY_ATTR_UNSPEC:
     case OVS_KEY_ATTR_CT_STATE:
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 626a82c..a124d6e 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -121,7 +121,6 @@ odp_action_len(uint16_t type)
     case OVS_ACTION_ATTR_SET_MASKED: return ATTR_LEN_VARIABLE;
     case OVS_ACTION_ATTR_SAMPLE: return ATTR_LEN_VARIABLE;
     case OVS_ACTION_ATTR_CT: return ATTR_LEN_VARIABLE;
-
     case OVS_ACTION_ATTR_UNSPEC:
     case __OVS_ACTION_ATTR_MAX:
         return ATTR_LEN_INVALID;
@@ -154,6 +153,8 @@ ovs_key_attr_to_string(enum ovs_key_attr attr, char *namebuf, size_t bufsize)
     case OVS_KEY_ATTR_IPV4: return "ipv4";
     case OVS_KEY_ATTR_IPV6: return "ipv6";
     case OVS_KEY_ATTR_TCP: return "tcp";
+    case OVS_KEY_ATTR_REDUCE_RWND: return "reduce_rwnd";
+    case OVS_KEY_ATTR_SET_RWND: return "set_rwnd";
     case OVS_KEY_ATTR_TCP_FLAGS: return "tcp_flags";
     case OVS_KEY_ATTR_UDP: return "udp";
     case OVS_KEY_ATTR_SCTP: return "sctp";
@@ -1793,6 +1794,8 @@ static const struct attr_len_tbl ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] =
     [OVS_KEY_ATTR_IPV4]      = { .len = sizeof(struct ovs_key_ipv4) },
     [OVS_KEY_ATTR_IPV6]      = { .len = sizeof(struct ovs_key_ipv6) },
     [OVS_KEY_ATTR_TCP]       = { .len = sizeof(struct ovs_key_tcp) },
+    [OVS_KEY_ATTR_REDUCE_RWND]  = { .len = 1 },
+    [OVS_KEY_ATTR_SET_RWND] = { .len = 2 },
     [OVS_KEY_ATTR_TCP_FLAGS] = { .len = 2 },
     [OVS_KEY_ATTR_UDP]       = { .len = sizeof(struct ovs_key_udp) },
     [OVS_KEY_ATTR_SCTP]      = { .len = sizeof(struct ovs_key_sctp) },
@@ -2872,6 +2875,22 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
         ds_chomp(ds, ',');
         break;
     }
+
+    case OVS_KEY_ATTR_REDUCE_RWND: {
+    	const struct ovs_key_reduce_rwnd *mask = ma ? nl_attr_get(ma) : NULL;
+    	uint8_t rate = nl_attr_get_u8(a);
+    	format_u8u(ds, "rate", rate, MASK(mask, rate), verbose);
+    	ds_chomp(ds, ',');
+    	break;
+    }
+
+    case OVS_KEY_ATTR_SET_RWND: {
+    	const struct ovs_key_set_rwnd *mask = ma ? nl_attr_get(ma) : NULL;
+    	ovs_be16 rwnd = nl_attr_get_be16(a);
+    	format_be16(ds, "rwnd", rwnd, MASK(mask, rwnd), verbose);
+    	break;
+    }
+
     case OVS_KEY_ATTR_TCP_FLAGS:
         if (!is_exact) {
             format_flags_masked(ds, NULL, packet_tcp_flag_to_string,
@@ -3393,6 +3412,22 @@ scan_tcp_flags(const char *s, ovs_be16 *key, ovs_be16 *mask)
     return 0;
 }
 
+static int
+scan_rwnd(const char *s, ovs_be16 *key, ovs_be16 *mask)
+{
+	OVS_NOT_REACHED();;
+	return 0;
+}
+
+static int
+scan_rate(const char *s, uint8_t *key, uint8_t *mask)
+{
+	OVS_NOT_REACHED();;
+	return 0;
+}
+

 static uint32_t
 ovs_to_odp_ct_state(uint8_t state)
 {
@@ -4112,6 +4147,9 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
         SCAN_FIELD("dst=", be16, tcp_dst);
     } SCAN_END(OVS_KEY_ATTR_TCP);
 
+    SCAN_SINGLE("reduce_rwnd(", uint8_t, rate, OVS_KEY_ATTR_REDUCE_RWND);
+    SCAN_SINGLE("set_rwnd(", ovs_be16, rwnd, OVS_KEY_ATTR_SET_RWND);
+
     SCAN_SINGLE("tcp_flags(", ovs_be16, tcp_flags, OVS_KEY_ATTR_TCP_FLAGS);
 
     SCAN_BEGIN("udp(", struct ovs_key_udp) {
@@ -5843,6 +5881,68 @@ commit_set_port_action(const struct flow *flow, struct flow *base_flow,
 }
 
 static void
+commit_reduce_rwnd_action(const struct flow *flow, struct flow *base_flow,
+                       struct ofpbuf *odp_actions, struct flow_wildcards *wc,
+                       bool use_masked)
+{
+    uint8_t key, mask, base;
+
+    /* Check if 'flow' really has an L3 header. */
+    if (!flow->nw_proto) {
+        return;
+    }
+
+    if (!is_ip_any(base_flow)) {
+        return;
+    }
+
+    if (flow->nw_proto != IPPROTO_TCP) {
+        return;
+    }
+
+    key = flow->rate;
+    base = base_flow->rate;
+    mask = wc->masks.rate;
+
+    if (commit(OVS_KEY_ATTR_REDUCE_RWND, use_masked, &key, &base, &mask, sizeof key,
+               odp_actions)) {
+    	base_flow->rate = base;
+    	wc->masks.rate = mask;
+    }
+}
+
+static void
+commit_set_rwnd_action(const struct flow *flow, struct flow *base_flow,
+                       struct ofpbuf *odp_actions, struct flow_wildcards *wc,
+                       bool use_masked)
+{
+    uint16_t key, mask, base;
+
+    /* Check if 'flow' really has an L3 header. */
+    if (!flow->nw_proto) {
+        return;
+    }
+
+    if (!is_ip_any(base_flow)) {
+        return;
+    }
+
+    if (flow->nw_proto != IPPROTO_TCP) {
+        return;
+    }
+
+    key = flow->rwnd;
+    base = base_flow->rwnd;
+    mask = wc->masks.rwnd;
+
+    if (commit(OVS_KEY_ATTR_SET_RWND, use_masked, &key, &base, &mask, sizeof key,
+               odp_actions)) {
+    	base_flow->rwnd = base;
+    	wc->masks.rwnd = mask;
+    }
+}
+
+static void
 commit_set_priority_action(const struct flow *flow, struct flow *base_flow,
                            struct ofpbuf *odp_actions,
                            struct flow_wildcards *wc,
@@ -5899,6 +5999,8 @@ commit_odp_actions(const struct flow *flow, struct flow *base,
     commit_set_ether_addr_action(flow, base, odp_actions, wc, use_masked);
     slow1 = commit_set_nw_action(flow, base, odp_actions, wc, use_masked);
     commit_set_port_action(flow, base, odp_actions, wc, use_masked);
+    commit_reduce_rwnd_action(flow, base, odp_actions, wc, use_masked);
+    commit_set_rwnd_action(flow, base, odp_actions, wc, use_masked);
     slow2 = commit_set_icmp_action(flow, base, odp_actions, wc);
     commit_mpls_action(flow, base, odp_actions);
     commit_vlan_action(flow->vlan_tci, base, odp_actions, wc);
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index 16f0f7c..3e2e334 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -229,6 +229,11 @@ enum ofp_raw_action_type {
     /* NX1.0-1.4(6): struct nx_action_reg_move, ... */
     NXAST_RAW_REG_MOVE,
 
+    /* OF1.3+(41): uint8_t. */
+    OFPAT_RAW_REDUCE_RWND,
+    /* OF1.3+(42): uint16_t. */
+    OFPAT_RAW_SET_RWND,
+
 /* ## ------------------------- ## */
 /* ## Nicira extension actions. ## */
 /* ## ------------------------- ## */
@@ -431,6 +436,8 @@ ofpact_next_flattened(const struct ofpact *ofpact)
     case OFPACT_WRITE_METADATA:
     case OFPACT_GOTO_TABLE:
     case OFPACT_NAT:
+    case OFPACT_REDUCE_RWND:
+    case OFPACT_SET_RWND:
         return ofpact_next(ofpact);
 
     case OFPACT_CT:
@@ -1995,6 +2002,18 @@ format_SET_IP_TTL(const struct ofpact_ip_ttl *a, struct ds *s)
 {
     ds_put_format(s, "%smod_nw_ttl:%s%d", colors.param, colors.end, a->ttl);
 }
+
+static void
+format_REDUCE_RWND(const struct ofpact_reduce_rwnd *a, struct ds *s)
+{
+    ds_put_format(s, "%sreduce_rwnd:%s%d", colors.param, colors.end, a->rate);
+}
+
+static void
+format_SET_RWND(const struct ofpact_set_rwnd *a, struct ds *s)
+{
+    ds_put_format(s, "%sset_rwnd:%s%d", colors.param, colors.end, a->rwnd);
+}
 
 /* Set TCP/UDP/SCTP port actions. */
 
@@ -2016,6 +2035,24 @@ decode_OFPAT_RAW_SET_TP_DST(ovs_be16 port,
     return 0;
 }
 
+static enum ofperr
+decode_OFPAT_RAW_REDUCE_RWND(uint8_t rate,
+                              enum ofp_version ofp_version OVS_UNUSED,
+                              struct ofpbuf *out)
+{
+    ofpact_put_REDUCE_RWND(out)->rate = rate;
+    return 0;
+}
+
+static enum ofperr
+decode_OFPAT_RAW_SET_RWND(uint16_t rwnd,
+                              enum ofp_version ofp_version OVS_UNUSED,
+                              struct ofpbuf *out)
+{
+    ofpact_put_SET_RWND(out)->rwnd = ntohs(rwnd);
+    return 0;
+}
+
 static void
 encode_SET_L4_port(const struct ofpact_l4_port *l4_port,
                    enum ofp_version ofp_version, enum ofp_raw_action_type raw,
@@ -2057,6 +2094,20 @@ encode_SET_L4_DST_PORT(const struct ofpact_l4_port *l4_port,
     encode_SET_L4_port(l4_port, ofp_version, OFPAT_RAW_SET_TP_DST, field, out);
 }
 
+static void
+encode_REDUCE_RWND(const struct ofpact_reduce_rwnd *reduce_rwnd,
+                  enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out)
+{
+    put_OFPAT_REDUCE_RWND(out, reduce_rwnd->rate);
+}
+
+static void
+encode_SET_RWND(const struct ofpact_set_rwnd *set_rwnd,
+                  enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out)
+{
+    put_OFPAT_SET_RWND(out, set_rwnd->rwnd);
+}
+
 static char * OVS_WARN_UNUSED_RESULT
 parse_SET_L4_SRC_PORT(char *arg, struct ofpbuf *ofpacts,
                       enum ofputil_protocol *usable_protocols OVS_UNUSED)
@@ -2084,6 +2135,39 @@ format_SET_L4_DST_PORT(const struct ofpact_l4_port *a, struct ds *s)
 {
     ds_put_format(s, "%smod_tp_dst:%s%d", colors.param, colors.end, a->port);
 }
+
+static char * OVS_WARN_UNUSED_RESULT
+parse_SET_RWND(char *arg, struct ofpbuf *ofpacts,
+                  enum ofputil_protocol *usable_protocols OVS_UNUSED)
+{
+    uint16_t rwnd;
+    char *error;
+
+    error = str_to_u16(arg, "rwnd", &rwnd);
+    if (error) {
+        return error;
+    }
+
+    ofpact_put_SET_RWND(ofpacts)->rwnd = rwnd;
+    return NULL;
+}
+
+static char * OVS_WARN_UNUSED_RESULT
+parse_REDUCE_RWND(char *arg, struct ofpbuf *ofpacts,
+                  enum ofputil_protocol *usable_protocols OVS_UNUSED)
+{
+    uint8_t rate;
+    char *error;
+
+    error = str_to_u8(arg, "rate", &rate);
+    if (error) {
+        return error;
+    }
+
+    ofpact_put_REDUCE_RWND(ofpacts)->rate = rate;
+    return NULL;
+}
+
 
 /* Action structure for OFPAT_COPY_FIELD. */
 struct ofp15_action_copy_field {
@@ -6156,6 +6240,8 @@ ofpact_is_set_or_move_action(const struct ofpact *a)
     case OFPACT_SET_TUNNEL:
     case OFPACT_SET_VLAN_PCP:
     case OFPACT_SET_VLAN_VID:
+    case OFPACT_SET_RWND:
+    case OFPACT_REDUCE_RWND:
         return true;
     case OFPACT_BUNDLE:
     case OFPACT_CLEAR_ACTIONS:
@@ -6229,6 +6315,8 @@ ofpact_is_allowed_in_actions_set(const struct ofpact *a)
     case OFPACT_SET_VLAN_PCP:
     case OFPACT_SET_VLAN_VID:
     case OFPACT_STRIP_VLAN:
+    case OFPACT_REDUCE_RWND:
+    case OFPACT_SET_RWND:
         return true;
 
     /* In general these actions are excluded because they are not part of
@@ -6472,6 +6560,8 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type)
     case OFPACT_DEBUG_RECIRC:
     case OFPACT_CT:
     case OFPACT_NAT:
+    case OFPACT_REDUCE_RWND:
+    case OFPACT_SET_RWND:
     default:
         return OVSINST_OFPIT11_APPLY_ACTIONS;
     }
@@ -6920,7 +7010,13 @@ ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a,
             inconsistent_match(usable_protocols);
         }
         return 0;
+    case OFPACT_REDUCE_RWND:
+    case OFPACT_SET_RWND:
+        if (!is_ip_any(flow) || (flow->nw_proto != IPPROTO_TCP)) {
+            inconsistent_match(usable_protocols);
+        }
 
+        return 0;
     case OFPACT_SET_IP_DSCP:
     case OFPACT_SET_IP_ECN:
     case OFPACT_SET_IP_TTL:
@@ -7457,6 +7553,9 @@ get_ofpact_map(enum ofp_version version)
         { OFPACT_SET_IP_TTL, 23 },
         { OFPACT_DEC_TTL, 24 },
         { OFPACT_SET_FIELD, 25 },
+
+        { OFPACT_REDUCE_RWND, 41 },
+        { OFPACT_SET_RWND, 42 },
         /* OF1.3+ OFPAT_PUSH_PBB (26) not supported. */
         /* OF1.3+ OFPAT_POP_PBB (27) not supported. */
         { 0, -1 },
@@ -7590,6 +7689,8 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port)
     case OFPACT_DEBUG_RECIRC:
     case OFPACT_CT:
     case OFPACT_NAT:
+    case OFPACT_REDUCE_RWND:
+    case OFPACT_SET_RWND:
     default:
         return false;
     }
@@ -7824,6 +7925,11 @@ ofpacts_parse__(char *str, struct ofpbuf *ofpacts,
             return xstrdup("apply_actions is the default instruction");
         } else if (ofputil_port_from_string(key, &port)) {
             ofpact_put_OUTPUT(ofpacts)->port = port;
+
+        } else if (!strcasecmp(key, "reduce_rwnd")) {
+            error = parse_REDUCE_RWND(value, ofpacts, usable_protocols);
+        } else if (!strcasecmp(key, "set_rwnd")) {
+            error = parse_SET_RWND(value, ofpacts, usable_protocols);
         } else {
             return xasprintf("unknown action %s", key);
         }
diff --git a/lib/packets.c b/lib/packets.c
index 990c407..772a991 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -1118,6 +1118,25 @@ packet_set_udp_port(struct dp_packet *packet, ovs_be16 src, ovs_be16 dst)
     }
 }
 
+void packet_set_rwnd(struct dp_packet *packet, ovs_be16 rwnd)
+{
+    struct tcp_header *th = dp_packet_l4(packet);
+    if (ntohs(rwnd) < ntohs(th->tcp_winsz)) {
+        th->tcp_csum = recalc_csum16(th->tcp_csum, th->tcp_winsz, rwnd);
+        th->tcp_winsz = rwnd;
+    }
+}
+
+void packet_reduce_rwnd(struct dp_packet *packet, uint8_t rate)
+{
+    if (rate > 0 && rate < 100) {
+        struct tcp_header *th = dp_packet_l4(packet);
+        ovs_be16 new_winsz = th->tcp_winsz * (rate / 100u);
+        th->tcp_csum = recalc_csum16(th->tcp_csum, th->tcp_winsz, new_winsz);
+        th->tcp_winsz = new_winsz;
+    }
+}
+
 /* Sets the SCTP source and destination port ('src' and 'dst' respectively) of
  * the SCTP header contained in 'packet'.  'packet' must be a valid SCTP packet
  * with its l4 offset properly populated. */
diff --git a/lib/packets.h b/lib/packets.h
index 21bd35c..b1c77d8 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -1098,6 +1098,9 @@ void packet_set_ipv6(struct dp_packet *, const ovs_be32 src[4],
                      ovs_be32 fl, uint8_t hlmit);
 void packet_set_tcp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst);
 void packet_set_udp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst);
+void packet_set_rwnd(struct dp_packet *, ovs_be16 rwnd);
+void packet_reduce_rwnd(struct dp_packet *, uint8_t rate);
+
 void packet_set_sctp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst);
 void packet_set_icmp(struct dp_packet *, uint8_t type, uint8_t code);
 void packet_set_nd(struct dp_packet *, const ovs_be32 target[4],
diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c
index 37992b4..29a7b80 100644
--- a/ofproto/ofproto-dpif-sflow.c
+++ b/ofproto/ofproto-dpif-sflow.c
@@ -1024,6 +1024,8 @@ sflow_read_set_action(const struct nlattr *attr,
     case OVS_KEY_ATTR_CT_LABELS:
     case OVS_KEY_ATTR_UNSPEC:
     case __OVS_KEY_ATTR_MAX:
+    case OVS_KEY_ATTR_REDUCE_RWND:
+    case OVS_KEY_ATTR_SET_RWND:
     default:
         break;
     }
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 4d10a54..3b21f17 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -4428,6 +4428,8 @@ freeze_unroll_actions(const struct ofpact *a, const struct ofpact *end,
         case OFPACT_DEBUG_RECIRC:
         case OFPACT_CT:
         case OFPACT_NAT:
+        case OFPACT_REDUCE_RWND:
+        case OFPACT_SET_RWND:
             /* These may not generate PACKET INs. */
             break;
 
@@ -4682,6 +4684,8 @@ recirc_for_mpls(const struct ofpact *a, struct xlate_ctx *ctx)
     case OFPACT_WRITE_ACTIONS:
     case OFPACT_WRITE_METADATA:
     case OFPACT_GOTO_TABLE:
+    case OFPACT_REDUCE_RWND:
+    case OFPACT_SET_RWND:
     default:
         break;
     }
@@ -4857,6 +4861,19 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             }
             break;
 
+        case OFPACT_REDUCE_RWND:
+            if (is_ip_any(flow)) {
+            	wc->masks.rate = 0xff;
+            	flow->rate = ofpact_get_REDUCE_RWND(a)->rate;
+            }
+            break;
+        case OFPACT_SET_RWND:
+            if (is_ip_any(flow)) {
+            	wc->masks.rwnd = 0xffff;
+            	flow->rwnd = ofpact_get_SET_RWND(a)->rwnd;
+            }
+            break;
+
         case OFPACT_RESUBMIT:
             /* Freezing complicates resubmit.  Some action in the flow
              * entry found by resubmit might trigger freezing.  If that
_______________________________________________
discuss mailing list
disc...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-discuss

Reply via email to