Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
O
openvswitch
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
SIG
nfv
rpms
openvswitch
Commits
3bede4e8
Verified
Commit
3bede4e8
authored
3 years ago
by
Louis Abel
Browse files
Options
Downloads
Patches
Plain Diff
import
parent
ace6950c
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
SOURCES/openvswitch-2.13.0.patch
+436
-59
436 additions, 59 deletions
SOURCES/openvswitch-2.13.0.patch
SPECS/openvswitch2.13.spec
+32
-1
32 additions, 1 deletion
SPECS/openvswitch2.13.spec
with
468 additions
and
60 deletions
SOURCES/openvswitch-2.13.0.patch
+
436
−
59
View file @
3bede4e8
...
@@ -1238,10 +1238,49 @@ index 92b52f6712..0dc2a7dbca 100644
...
@@ -1238,10 +1238,49 @@ index 92b52f6712..0dc2a7dbca 100644
OVS_CHECK_PRAGMA_MESSAGE
OVS_CHECK_PRAGMA_MESSAGE
AC_SUBST([OVS_CFLAGS])
AC_SUBST([OVS_CFLAGS])
diff --git a/datapath-windows/ovsext/Actions.c b/datapath-windows/ovsext/Actions.c
diff --git a/datapath-windows/ovsext/Actions.c b/datapath-windows/ovsext/Actions.c
index 5c9b5c3a0c..
f1f2c03197
100644
index 5c9b5c3a0c..
b49243006f
100644
--- a/datapath-windows/ovsext/Actions.c
--- a/datapath-windows/ovsext/Actions.c
+++ b/datapath-windows/ovsext/Actions.c
+++ b/datapath-windows/ovsext/Actions.c
@@ -1259,6 +1259,7 @@ OvsActionMplsPush(OvsForwardingContext *ovsFwdCtx,
@@ -1112,9 +1112,9 @@ OvsPopFieldInPacketBuf(OvsForwardingContext *ovsFwdCtx,
* should split the function and refactor. */
if (!bufferData) {
EthHdr *ethHdr = (EthHdr *)bufferStart;
- /* If the frame is not VLAN make it a no op */
if (ethHdr->Type != ETH_TYPE_802_1PQ_NBO) {
- return NDIS_STATUS_SUCCESS;
+ OVS_LOG_ERROR("Invalid ethHdr type %u, nbl %p", ethHdr->Type, ovsFwdCtx->curNbl);
+ return NDIS_STATUS_INVALID_PACKET;
}
}
RtlMoveMemory(bufferStart + shiftLength, bufferStart, shiftOffset);
@@ -1137,6 +1137,9 @@ OvsPopFieldInPacketBuf(OvsForwardingContext *ovsFwdCtx,
static __inline NDIS_STATUS
OvsPopVlanInPktBuf(OvsForwardingContext *ovsFwdCtx)
{
+ NDIS_STATUS status;
+ OVS_PACKET_HDR_INFO* layers = &ovsFwdCtx->layers;
+
/*
* Declare a dummy vlanTag structure since we need to compute the size
* of shiftLength. The NDIS one is a unionized structure.
@@ -1145,7 +1148,15 @@ OvsPopVlanInPktBuf(OvsForwardingContext *ovsFwdCtx)
UINT32 shiftLength = sizeof(vlanTag.TagHeader);
UINT32 shiftOffset = sizeof(DL_EUI48) + sizeof(DL_EUI48);
- return OvsPopFieldInPacketBuf(ovsFwdCtx, shiftOffset, shiftLength, NULL);
+ status = OvsPopFieldInPacketBuf(ovsFwdCtx, shiftOffset, shiftLength,
+ NULL);
+
+ if (status == NDIS_STATUS_SUCCESS) {
+ layers->l3Offset -= (UINT16) shiftLength;
+ layers->l4Offset -= (UINT16) shiftLength;
+ }
+
+ return status;
}
@@ -1259,6 +1270,7 @@ OvsActionMplsPush(OvsForwardingContext *ovsFwdCtx,
*/
*/
static __inline NDIS_STATUS
static __inline NDIS_STATUS
OvsUpdateEthHeader(OvsForwardingContext *ovsFwdCtx,
OvsUpdateEthHeader(OvsForwardingContext *ovsFwdCtx,
...
@@ -1249,7 +1288,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
...
@@ -1249,7 +1288,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
const struct ovs_key_ethernet *ethAttr)
const struct ovs_key_ethernet *ethAttr)
{
{
PNET_BUFFER curNb;
PNET_BUFFER curNb;
@@ -1285,9 +12
86
,11 @@ OvsUpdateEthHeader(OvsForwardingContext *ovsFwdCtx,
@@ -1285,9 +12
97
,11 @@ OvsUpdateEthHeader(OvsForwardingContext *ovsFwdCtx,
}
}
ethHdr = (EthHdr *)(bufferStart + NET_BUFFER_CURRENT_MDL_OFFSET(curNb));
ethHdr = (EthHdr *)(bufferStart + NET_BUFFER_CURRENT_MDL_OFFSET(curNb));
...
@@ -1264,7 +1303,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
...
@@ -1264,7 +1303,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
return NDIS_STATUS_SUCCESS;
return NDIS_STATUS_SUCCESS;
}
}
@@ -1376,6 +13
7
9,7 @@ PUINT8 OvsGetHeaderBySize(OvsForwardingContext *ovsFwdCtx,
@@ -1376,6 +139
0
,7 @@ PUINT8 OvsGetHeaderBySize(OvsForwardingContext *ovsFwdCtx,
*/
*/
NDIS_STATUS
NDIS_STATUS
OvsUpdateUdpPorts(OvsForwardingContext *ovsFwdCtx,
OvsUpdateUdpPorts(OvsForwardingContext *ovsFwdCtx,
...
@@ -1272,7 +1311,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
...
@@ -1272,7 +1311,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
const struct ovs_key_udp *udpAttr)
const struct ovs_key_udp *udpAttr)
{
{
PUINT8 bufferStart;
PUINT8 bufferStart;
@@ -1400,15 +14
04
,19 @@ OvsUpdateUdpPorts(OvsForwardingContext *ovsFwdCtx,
@@ -1400,15 +14
15
,19 @@ OvsUpdateUdpPorts(OvsForwardingContext *ovsFwdCtx,
udpHdr->check = ChecksumUpdate16(udpHdr->check, udpHdr->source,
udpHdr->check = ChecksumUpdate16(udpHdr->check, udpHdr->source,
udpAttr->udp_src);
udpAttr->udp_src);
udpHdr->source = udpAttr->udp_src;
udpHdr->source = udpAttr->udp_src;
...
@@ -1292,7 +1331,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
...
@@ -1292,7 +1331,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
}
}
return NDIS_STATUS_SUCCESS;
return NDIS_STATUS_SUCCESS;
@@ -1423,6 +14
31
,7 @@ OvsUpdateUdpPorts(OvsForwardingContext *ovsFwdCtx,
@@ -1423,6 +14
42
,7 @@ OvsUpdateUdpPorts(OvsForwardingContext *ovsFwdCtx,
*/
*/
NDIS_STATUS
NDIS_STATUS
OvsUpdateTcpPorts(OvsForwardingContext *ovsFwdCtx,
OvsUpdateTcpPorts(OvsForwardingContext *ovsFwdCtx,
...
@@ -1300,7 +1339,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
...
@@ -1300,7 +1339,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
const struct ovs_key_tcp *tcpAttr)
const struct ovs_key_tcp *tcpAttr)
{
{
PUINT8 bufferStart;
PUINT8 bufferStart;
@@ -1447,11 +14
5
6,13 @@ OvsUpdateTcpPorts(OvsForwardingContext *ovsFwdCtx,
@@ -1447,11 +146
7
,13 @@ OvsUpdateTcpPorts(OvsForwardingContext *ovsFwdCtx,
tcpHdr->check = ChecksumUpdate16(tcpHdr->check, tcpHdr->source,
tcpHdr->check = ChecksumUpdate16(tcpHdr->check, tcpHdr->source,
tcpAttr->tcp_src);
tcpAttr->tcp_src);
tcpHdr->source = tcpAttr->tcp_src;
tcpHdr->source = tcpAttr->tcp_src;
...
@@ -1314,7 +1353,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
...
@@ -1314,7 +1353,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
}
}
return NDIS_STATUS_SUCCESS;
return NDIS_STATUS_SUCCESS;
@@ -1539,9 +15
50
,21 @@ OvsUpdateAddressAndPort(OvsForwardingContext *ovsFwdCtx,
@@ -1539,9 +15
61
,21 @@ OvsUpdateAddressAndPort(OvsForwardingContext *ovsFwdCtx,
if (tcpHdr) {
if (tcpHdr) {
portField = &tcpHdr->dest;
portField = &tcpHdr->dest;
checkField = &tcpHdr->check;
checkField = &tcpHdr->check;
...
@@ -1336,7 +1375,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
...
@@ -1336,7 +1375,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
}
}
}
}
@@ -1579,6 +16
02
,7 @@ OvsUpdateAddressAndPort(OvsForwardingContext *ovsFwdCtx,
@@ -1579,6 +16
13
,7 @@ OvsUpdateAddressAndPort(OvsForwardingContext *ovsFwdCtx,
*/
*/
NDIS_STATUS
NDIS_STATUS
OvsUpdateIPv4Header(OvsForwardingContext *ovsFwdCtx,
OvsUpdateIPv4Header(OvsForwardingContext *ovsFwdCtx,
...
@@ -1344,7 +1383,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
...
@@ -1344,7 +1383,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
const struct ovs_key_ipv4 *ipAttr)
const struct ovs_key_ipv4 *ipAttr)
{
{
PUINT8 bufferStart;
PUINT8 bufferStart;
@@ -1632,6 +16
5
6,7 @@ OvsUpdateIPv4Header(OvsForwardingContext *ovsFwdCtx,
@@ -1632,6 +166
7
,7 @@ OvsUpdateIPv4Header(OvsForwardingContext *ovsFwdCtx,
ipAttr->ipv4_src);
ipAttr->ipv4_src);
}
}
ipHdr->saddr = ipAttr->ipv4_src;
ipHdr->saddr = ipAttr->ipv4_src;
...
@@ -1352,7 +1391,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
...
@@ -1352,7 +1391,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
}
}
if (ipHdr->daddr != ipAttr->ipv4_dst) {
if (ipHdr->daddr != ipAttr->ipv4_dst) {
if (tcpHdr) {
if (tcpHdr) {
@@ -1647,6 +16
72
,7 @@ OvsUpdateIPv4Header(OvsForwardingContext *ovsFwdCtx,
@@ -1647,6 +16
83
,7 @@ OvsUpdateIPv4Header(OvsForwardingContext *ovsFwdCtx,
ipAttr->ipv4_dst);
ipAttr->ipv4_dst);
}
}
ipHdr->daddr = ipAttr->ipv4_dst;
ipHdr->daddr = ipAttr->ipv4_dst;
...
@@ -1360,7 +1399,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
...
@@ -1360,7 +1399,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
}
}
if (ipHdr->protocol != ipAttr->ipv4_proto) {
if (ipHdr->protocol != ipAttr->ipv4_proto) {
UINT16 oldProto = (ipHdr->protocol << 16) & 0xff00;
UINT16 oldProto = (ipHdr->protocol << 16) & 0xff00;
@@ -1661,6 +168
7
,7 @@ OvsUpdateIPv4Header(OvsForwardingContext *ovsFwdCtx,
@@ -1661,6 +16
9
8,7 @@ OvsUpdateIPv4Header(OvsForwardingContext *ovsFwdCtx,
ipHdr->check = ChecksumUpdate16(ipHdr->check, oldProto, newProto);
ipHdr->check = ChecksumUpdate16(ipHdr->check, oldProto, newProto);
}
}
ipHdr->protocol = ipAttr->ipv4_proto;
ipHdr->protocol = ipAttr->ipv4_proto;
...
@@ -1368,7 +1407,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
...
@@ -1368,7 +1407,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
}
}
if (ipHdr->ttl != ipAttr->ipv4_ttl) {
if (ipHdr->ttl != ipAttr->ipv4_ttl) {
UINT16 oldTtl = (ipHdr->ttl) & 0xff;
UINT16 oldTtl = (ipHdr->ttl) & 0xff;
@@ -1669,6 +1
696
,7 @@ OvsUpdateIPv4Header(OvsForwardingContext *ovsFwdCtx,
@@ -1669,6 +1
707
,7 @@ OvsUpdateIPv4Header(OvsForwardingContext *ovsFwdCtx,
ipHdr->check = ChecksumUpdate16(ipHdr->check, oldTtl, newTtl);
ipHdr->check = ChecksumUpdate16(ipHdr->check, oldTtl, newTtl);
}
}
ipHdr->ttl = ipAttr->ipv4_ttl;
ipHdr->ttl = ipAttr->ipv4_ttl;
...
@@ -1376,7 +1415,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
...
@@ -1376,7 +1415,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
}
}
return NDIS_STATUS_SUCCESS;
return NDIS_STATUS_SUCCESS;
@@ -1691,12 +17
19
,12 @@ OvsExecuteSetAction(OvsForwardingContext *ovsFwdCtx,
@@ -1691,12 +17
30
,12 @@ OvsExecuteSetAction(OvsForwardingContext *ovsFwdCtx,
switch (type) {
switch (type) {
case OVS_KEY_ATTR_ETHERNET:
case OVS_KEY_ATTR_ETHERNET:
...
@@ -1391,7 +1430,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
...
@@ -1391,7 +1430,7 @@ index 5c9b5c3a0c..f1f2c03197 100644
NlAttrGetUnspec(a, sizeof(struct ovs_key_ipv4)));
NlAttrGetUnspec(a, sizeof(struct ovs_key_ipv4)));
break;
break;
@@ -1709,16 +17
37
,17 @@ OvsExecuteSetAction(OvsForwardingContext *ovsFwdCtx,
@@ -1709,16 +17
48
,17 @@ OvsExecuteSetAction(OvsForwardingContext *ovsFwdCtx,
status = SUCCEEDED(convertStatus) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE;
status = SUCCEEDED(convertStatus) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE;
ASSERT(status == NDIS_STATUS_SUCCESS);
ASSERT(status == NDIS_STATUS_SUCCESS);
RtlCopyMemory(&ovsFwdCtx->tunKey, &tunKey, sizeof ovsFwdCtx->tunKey);
RtlCopyMemory(&ovsFwdCtx->tunKey, &tunKey, sizeof ovsFwdCtx->tunKey);
...
@@ -1411,6 +1450,46 @@ index 5c9b5c3a0c..f1f2c03197 100644
...
@@ -1411,6 +1450,46 @@ index 5c9b5c3a0c..f1f2c03197 100644
NlAttrGetUnspec(a, sizeof(struct ovs_key_tcp)));
NlAttrGetUnspec(a, sizeof(struct ovs_key_tcp)));
break;
break;
@@ -1763,9 +1803,11 @@ OvsExecuteRecirc(OvsForwardingContext *ovsFwdCtx,
}
if (newNbl) {
- deferredAction = OvsAddDeferredActions(newNbl, key, NULL);
+ deferredAction = OvsAddDeferredActions(newNbl, key, &(ovsFwdCtx->layers),
+ NULL);
} else {
- deferredAction = OvsAddDeferredActions(ovsFwdCtx->curNbl, key, NULL);
+ deferredAction = OvsAddDeferredActions(ovsFwdCtx->curNbl, key,
+ &(ovsFwdCtx->layers), NULL);
}
if (deferredAction) {
@@ -1917,7 +1959,7 @@ OvsExecuteSampleAction(OvsForwardingContext *ovsFwdCtx,
return STATUS_SUCCESS;
}
- if (!OvsAddDeferredActions(newNbl, key, a)) {
+ if (!OvsAddDeferredActions(newNbl, key, &(ovsFwdCtx->layers), a)) {
OVS_LOG_INFO(
"Deferred actions limit reached, dropping sample action.");
OvsCompleteNBL(ovsFwdCtx->switchContext, newNbl, TRUE);
@@ -2053,6 +2095,7 @@ OvsDoExecuteActions(POVS_SWITCH_CONTEXT switchContext,
*/
status = OvsPopVlanInPktBuf(&ovsFwdCtx);
if (status != NDIS_STATUS_SUCCESS) {
+ OVS_LOG_ERROR("OVS-pop vlan action failed status = %lu", status);
dropReason = L"OVS-pop vlan action failed";
goto dropit;
}
@@ -2302,7 +2345,7 @@ OvsActionsExecute(POVS_SWITCH_CONTEXT switchContext,
if (status == STATUS_SUCCESS) {
status = OvsProcessDeferredActions(switchContext, completionList,
- portNo, sendFlags, layers);
+ portNo, sendFlags, NULL);
}
return status;
diff --git a/datapath-windows/ovsext/Actions.h b/datapath-windows/ovsext/Actions.h
diff --git a/datapath-windows/ovsext/Actions.h b/datapath-windows/ovsext/Actions.h
index fd050d5dd8..bc12e1166d 100644
index fd050d5dd8..bc12e1166d 100644
--- a/datapath-windows/ovsext/Actions.h
--- a/datapath-windows/ovsext/Actions.h
...
@@ -1510,6 +1589,97 @@ index bc6580d708..b0932186af 100644
...
@@ -1510,6 +1589,97 @@ index bc6580d708..b0932186af 100644
} CT_UPDATE_RES;
} CT_UPDATE_RES;
/* Metadata mark for masked write to conntrack mark */
/* Metadata mark for masked write to conntrack mark */
diff --git a/datapath-windows/ovsext/Recirc.c b/datapath-windows/ovsext/Recirc.c
index 2febf060dd..a32b75352b 100644
--- a/datapath-windows/ovsext/Recirc.c
+++ b/datapath-windows/ovsext/Recirc.c
@@ -277,16 +277,23 @@ OvsDeferredActionsQueuePush(POVS_DEFERRED_ACTION_QUEUE queue)
POVS_DEFERRED_ACTION
OvsAddDeferredActions(PNET_BUFFER_LIST nbl,
OvsFlowKey *key,
+ POVS_PACKET_HDR_INFO layers,
const PNL_ATTR actions)
{
POVS_DEFERRED_ACTION_QUEUE queue = OvsDeferredActionsQueueGet();
POVS_DEFERRED_ACTION deferredAction = NULL;
+ OVS_PACKET_HDR_INFO layersInit = { 0 };
deferredAction = OvsDeferredActionsQueuePush(queue);
if (deferredAction) {
deferredAction->nbl = nbl;
deferredAction->actions = actions;
deferredAction->key = *key;
+ if (layers) {
+ deferredAction->layers = *layers;
+ } else {
+ deferredAction->layers = layersInit;
+ }
}
return deferredAction;
@@ -309,9 +316,16 @@ OvsProcessDeferredActions(POVS_SWITCH_CONTEXT switchContext,
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
POVS_DEFERRED_ACTION_QUEUE queue = OvsDeferredActionsQueueGet();
POVS_DEFERRED_ACTION deferredAction = NULL;
+ POVS_PACKET_HDR_INFO layersDeferred = NULL;
/* Process all deferred actions. */
while ((deferredAction = OvsDeferredActionsQueuePop(queue)) != NULL) {
+ if (layers) {
+ layersDeferred = layers;
+ } else {
+ layersDeferred = &(deferredAction->layers);
+ }
+
if (deferredAction->actions) {
status = OvsDoExecuteActions(switchContext,
completionList,
@@ -319,7 +333,7 @@ OvsProcessDeferredActions(POVS_SWITCH_CONTEXT switchContext,
portNo,
sendFlags,
&deferredAction->key, NULL,
- layers, deferredAction->actions,
+ layersDeferred, deferredAction->actions,
NlAttrGetSize(deferredAction->actions));
} else {
status = OvsDoRecirc(switchContext,
@@ -327,7 +341,7 @@ OvsProcessDeferredActions(POVS_SWITCH_CONTEXT switchContext,
deferredAction->nbl,
&deferredAction->key,
portNo,
- layers);
+ layersDeferred);
}
}
diff --git a/datapath-windows/ovsext/Recirc.h b/datapath-windows/ovsext/Recirc.h
index 2b314ce274..74130a4600 100644
--- a/datapath-windows/ovsext/Recirc.h
+++ b/datapath-windows/ovsext/Recirc.h
@@ -18,6 +18,7 @@
#define __RECIRC_H_ 1
#include "Actions.h"
+#include "NetProto.h"
#define DEFERRED_ACTION_QUEUE_SIZE 10
#define DEFERRED_ACTION_EXEC_LEVEL 4
@@ -26,6 +27,7 @@ typedef struct _OVS_DEFERRED_ACTION {
PNET_BUFFER_LIST nbl;
PNL_ATTR actions;
OvsFlowKey key;
+ OVS_PACKET_HDR_INFO layers;
} OVS_DEFERRED_ACTION, *POVS_DEFERRED_ACTION;
/*
@@ -52,6 +54,7 @@ OvsProcessDeferredActions(POVS_SWITCH_CONTEXT switchContext,
POVS_DEFERRED_ACTION
OvsAddDeferredActions(PNET_BUFFER_LIST packet,
OvsFlowKey *key,
+ POVS_PACKET_HDR_INFO layers,
const PNL_ATTR actions);
/*
diff --git a/datapath-windows/ovsext/ovsext.vcxproj b/datapath-windows/ovsext/ovsext.vcxproj
diff --git a/datapath-windows/ovsext/ovsext.vcxproj b/datapath-windows/ovsext/ovsext.vcxproj
index d50a126b43..18f884f41b 100644
index d50a126b43..18f884f41b 100644
--- a/datapath-windows/ovsext/ovsext.vcxproj
--- a/datapath-windows/ovsext/ovsext.vcxproj
...
@@ -79929,6 +80099,18 @@ index 5289a70f6e..cf009f8264 100644
...
@@ -79929,6 +80099,18 @@ index 5289a70f6e..cf009f8264 100644
#define OVS_LOCKABLE __attribute__((lockable))
#define OVS_LOCKABLE __attribute__((lockable))
#define OVS_REQ_RDLOCK(...) __attribute__((shared_locks_required(__VA_ARGS__)))
#define OVS_REQ_RDLOCK(...) __attribute__((shared_locks_required(__VA_ARGS__)))
#define OVS_ACQ_RDLOCK(...) __attribute__((shared_lock_function(__VA_ARGS__)))
#define OVS_ACQ_RDLOCK(...) __attribute__((shared_lock_function(__VA_ARGS__)))
diff --git a/include/openvswitch/meta-flow.h b/include/openvswitch/meta-flow.h
index 1f81d830e7..4b9893388b 100644
--- a/include/openvswitch/meta-flow.h
+++ b/include/openvswitch/meta-flow.h
@@ -2277,6 +2277,7 @@ void mf_set_flow_value_masked(const struct mf_field *,
const union mf_value *mask,
struct flow *);
bool mf_is_tun_metadata(const struct mf_field *);
+bool mf_is_frozen_metadata(const struct mf_field *);
bool mf_is_pipeline_field(const struct mf_field *);
bool mf_is_set(const struct mf_field *, const struct flow *);
void mf_mask_field(const struct mf_field *, struct flow_wildcards *);
diff --git a/ipsec/ovs-monitor-ipsec.in b/ipsec/ovs-monitor-ipsec.in
diff --git a/ipsec/ovs-monitor-ipsec.in b/ipsec/ovs-monitor-ipsec.in
index 37e3703245..668507fd37 100755
index 37e3703245..668507fd37 100755
--- a/ipsec/ovs-monitor-ipsec.in
--- a/ipsec/ovs-monitor-ipsec.in
...
@@ -80845,7 +81027,7 @@ index 68c33a0f96..9b251f81fa 100644
...
@@ -80845,7 +81027,7 @@ index 68c33a0f96..9b251f81fa 100644
* Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License.
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index d393aab5e3..
2fb0d418b1
100644
index d393aab5e3..
a73102ea98
100644
--- a/lib/dpif-netdev.c
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -83,9 +83,9 @@
@@ -83,9 +83,9 @@
...
@@ -81154,22 +81336,32 @@ index d393aab5e3..2fb0d418b1 100644
...
@@ -81154,22 +81336,32 @@ index d393aab5e3..2fb0d418b1 100644
dp_netdev_execute_actions(pmd, &pp, false, execute->flow,
dp_netdev_execute_actions(pmd, &pp, false, execute->flow,
execute->actions, execute->actions_len);
execute->actions, execute->actions_len);
dp_netdev_pmd_flush_output_packets(pmd, true);
dp_netdev_pmd_flush_output_packets(pmd, true);
@@ -3841,6 +3944,
1
4 @@ dpif_netdev_execute(struct dpif *dpif, struct dpif_execute *execute)
@@ -3841,6 +3944,
2
4 @@ dpif_netdev_execute(struct dpif *dpif, struct dpif_execute *execute)
dp_netdev_pmd_unref(pmd);
dp_netdev_pmd_unref(pmd);
}
}
+ if (dp_packet_batch_size(&pp)) {
+ if (dp_packet_batch_size(&pp)
== 1
) {
+ /* Packet wasn't dropped during the execution. Swapping content with
+ /* Packet wasn't dropped during the execution. Swapping content with
+ * the original packet, because the caller might expect actions to
+ * the original packet, because the caller might expect actions to
+ * modify it. */
+ * modify it. Uisng the packet from a batch instead of 'packet_clone'
+ dp_packet_swap(execute->packet, packet_clone);
+ * because it maybe stolen and replaced by other packet, e.g. by
+ * the fragmentation engine. */
+ dp_packet_swap(execute->packet, pp.packets[0]);
+ dp_packet_delete_batch(&pp, true);
+ } else if (dp_packet_batch_size(&pp)) {
+ /* FIXME: We have more packets than expected. Likely, we got IP
+ * fragments of the reassembled packet. Dropping them here as we have
+ * no way to get them to the caller. It might be that all the required
+ * actions with them are already executed, but it also might not be a
+ * case, e.g. if dpif_netdev_execute() called to execute a single
+ * tunnel push. */
+ dp_packet_delete_batch(&pp, true);
+ dp_packet_delete_batch(&pp, true);
+ }
+ }
+
+
return 0;
return 0;
}
}
@@ -3875,11 +39
8
6,12 @@ dpif_netdev_operate(struct dpif *dpif, struct dpif_op **ops, size_t n_ops,
@@ -3875,11 +39
9
6,12 @@ dpif_netdev_operate(struct dpif *dpif, struct dpif_op **ops, size_t n_ops,
/* Enable or Disable PMD auto load balancing. */
/* Enable or Disable PMD auto load balancing. */
static void
static void
...
@@ -81183,7 +81375,7 @@ index d393aab5e3..2fb0d418b1 100644
...
@@ -81183,7 +81375,7 @@ index d393aab5e3..2fb0d418b1 100644
bool enable_alb = false;
bool enable_alb = false;
bool multi_rxq = false;
bool multi_rxq = false;
@@ -3906,18 +40
1
8,24 @@ set_pmd_auto_lb(struct dp_netdev *dp)
@@ -3906,18 +40
2
8,24 @@ set_pmd_auto_lb(struct dp_netdev *dp)
enable_alb = enable_alb && pmd_rxq_assign_cyc &&
enable_alb = enable_alb && pmd_rxq_assign_cyc &&
pmd_alb->auto_lb_requested;
pmd_alb->auto_lb_requested;
...
@@ -81212,7 +81404,7 @@ index d393aab5e3..2fb0d418b1 100644
...
@@ -81212,7 +81404,7 @@ index d393aab5e3..2fb0d418b1 100644
}
}
/* Applies datapath configuration from the database. Some of the changes are
/* Applies datapath configuration from the database. Some of the changes are
@@ -3935,6 +40
5
3,9 @@ dpif_netdev_set_config(struct dpif *dpif, const struct smap *other_config)
@@ -3935,6 +40
6
3,9 @@ dpif_netdev_set_config(struct dpif *dpif, const struct smap *other_config)
uint32_t insert_min, cur_min;
uint32_t insert_min, cur_min;
uint32_t tx_flush_interval, cur_tx_flush_interval;
uint32_t tx_flush_interval, cur_tx_flush_interval;
uint64_t rebalance_intvl;
uint64_t rebalance_intvl;
...
@@ -81222,7 +81414,7 @@ index d393aab5e3..2fb0d418b1 100644
...
@@ -81222,7 +81414,7 @@ index d393aab5e3..2fb0d418b1 100644
tx_flush_interval = smap_get_int(other_config, "tx-flush-interval",
tx_flush_interval = smap_get_int(other_config, "tx-flush-interval",
DEFAULT_TX_FLUSH_INTERVAL);
DEFAULT_TX_FLUSH_INTERVAL);
@@ -4012,7 +41
3
3,7 @@ dpif_netdev_set_config(struct dpif *dpif, const struct smap *other_config)
@@ -4012,7 +41
4
3,7 @@ dpif_netdev_set_config(struct dpif *dpif, const struct smap *other_config)
false);
false);
rebalance_intvl = smap_get_int(other_config, "pmd-auto-lb-rebal-interval",
rebalance_intvl = smap_get_int(other_config, "pmd-auto-lb-rebal-interval",
...
@@ -81231,7 +81423,7 @@ index d393aab5e3..2fb0d418b1 100644
...
@@ -81231,7 +81423,7 @@ index d393aab5e3..2fb0d418b1 100644
/* Input is in min, convert it to msec. */
/* Input is in min, convert it to msec. */
rebalance_intvl =
rebalance_intvl =
@@ -4020,9 +41
4
1,38 @@ dpif_netdev_set_config(struct dpif *dpif, const struct smap *other_config)
@@ -4020,9 +41
5
1,38 @@ dpif_netdev_set_config(struct dpif *dpif, const struct smap *other_config)
if (pmd_alb->rebalance_intvl != rebalance_intvl) {
if (pmd_alb->rebalance_intvl != rebalance_intvl) {
pmd_alb->rebalance_intvl = rebalance_intvl;
pmd_alb->rebalance_intvl = rebalance_intvl;
...
@@ -81273,7 +81465,7 @@ index d393aab5e3..2fb0d418b1 100644
...
@@ -81273,7 +81465,7 @@ index d393aab5e3..2fb0d418b1 100644
return 0;
return 0;
}
}
@@ -4493,6 +46
4
3,12 @@ struct rr_numa {
@@ -4493,6 +46
5
3,12 @@ struct rr_numa {
bool idx_inc;
bool idx_inc;
};
};
...
@@ -81286,7 +81478,7 @@ index d393aab5e3..2fb0d418b1 100644
...
@@ -81286,7 +81478,7 @@ index d393aab5e3..2fb0d418b1 100644
static struct rr_numa *
static struct rr_numa *
rr_numa_list_lookup(struct rr_numa_list *rr, int numa_id)
rr_numa_list_lookup(struct rr_numa_list *rr, int numa_id)
{
{
@@ -4940,9 +50
9
6,17 @@ reconfigure_datapath(struct dp_netdev *dp)
@@ -4940,9 +5
1
06,17 @@ reconfigure_datapath(struct dp_netdev *dp)
/* Check for all the ports that need reconfiguration. We cache this in
/* Check for all the ports that need reconfiguration. We cache this in
* 'port->need_reconfigure', because netdev_is_reconf_required() can
* 'port->need_reconfigure', because netdev_is_reconf_required() can
...
@@ -81306,7 +81498,7 @@ index d393aab5e3..2fb0d418b1 100644
...
@@ -81306,7 +81498,7 @@ index d393aab5e3..2fb0d418b1 100644
port->need_reconfigure = true;
port->need_reconfigure = true;
}
}
}
}
@@ -5076,7 +52
4
0,7 @@ reconfigure_datapath(struct dp_netdev *dp)
@@ -5076,7 +52
5
0,7 @@ reconfigure_datapath(struct dp_netdev *dp)
reload_affected_pmds(dp);
reload_affected_pmds(dp);
/* Check if PMD Auto LB is to be enabled */
/* Check if PMD Auto LB is to be enabled */
...
@@ -81315,7 +81507,7 @@ index d393aab5e3..2fb0d418b1 100644
...
@@ -81315,7 +81507,7 @@ index d393aab5e3..2fb0d418b1 100644
}
}
/* Returns true if one of the netdevs in 'dp' requires a reconfiguration */
/* Returns true if one of the netdevs in 'dp' requires a reconfiguration */
@@ -5189,10 +53
5
3,17 @@ get_dry_run_variance(struct dp_netdev *dp, uint32_t *core_list,
@@ -5189,10 +53
6
3,17 @@ get_dry_run_variance(struct dp_netdev *dp, uint32_t *core_list,
for (int i = 0; i < n_rxqs; i++) {
for (int i = 0; i < n_rxqs; i++) {
int numa_id = netdev_get_numa_id(rxqs[i]->port->netdev);
int numa_id = netdev_get_numa_id(rxqs[i]->port->netdev);
numa = rr_numa_list_lookup(&rr, numa_id);
numa = rr_numa_list_lookup(&rr, numa_id);
...
@@ -81336,7 +81528,7 @@ index d393aab5e3..2fb0d418b1 100644
...
@@ -81336,7 +81528,7 @@ index d393aab5e3..2fb0d418b1 100644
goto cleanup;
goto cleanup;
}
}
@@ -5320,7 +5
49
1,7 @@ pmd_rebalance_dry_run(struct dp_netdev *dp)
@@ -5320,7 +5
50
1,7 @@ pmd_rebalance_dry_run(struct dp_netdev *dp)
improvement =
improvement =
((curr_variance - new_variance) * 100) / curr_variance;
((curr_variance - new_variance) * 100) / curr_variance;
}
}
...
@@ -81345,7 +81537,7 @@ index d393aab5e3..2fb0d418b1 100644
...
@@ -81345,7 +81537,7 @@ index d393aab5e3..2fb0d418b1 100644
ret = false;
ret = false;
}
}
}
}
@@ -5787,12 +59
5
8,14 @@ dp_netdev_run_meter(struct dp_netdev *dp, struct dp_packet_batch *packets_,
@@ -5787,12 +59
6
8,14 @@ dp_netdev_run_meter(struct dp_netdev *dp, struct dp_packet_batch *packets_,
/* Update all bands and find the one hit with the highest rate for each
/* Update all bands and find the one hit with the highest rate for each
* packet (if any). */
* packet (if any). */
for (int m = 0; m < meter->n_bands; ++m) {
for (int m = 0; m < meter->n_bands; ++m) {
...
@@ -81364,7 +81556,7 @@ index d393aab5e3..2fb0d418b1 100644
...
@@ -81364,7 +81556,7 @@ index d393aab5e3..2fb0d418b1 100644
}
}
/* Drain the bucket for all the packets, if possible. */
/* Drain the bucket for all the packets, if possible. */
@@ -5810,8 +59
8
3,8 @@ dp_netdev_run_meter(struct dp_netdev *dp, struct dp_packet_batch *packets_,
@@ -5810,8 +59
9
3,8 @@ dp_netdev_run_meter(struct dp_netdev *dp, struct dp_packet_batch *packets_,
* (Only one band will be fired by a packet, and that
* (Only one band will be fired by a packet, and that
* can be different for each packet.) */
* can be different for each packet.) */
for (int i = band_exceeded_pkt; i < cnt; i++) {
for (int i = band_exceeded_pkt; i < cnt; i++) {
...
@@ -81375,7 +81567,7 @@ index d393aab5e3..2fb0d418b1 100644
...
@@ -81375,7 +81567,7 @@ index d393aab5e3..2fb0d418b1 100644
exceeded_band[i] = m;
exceeded_band[i] = m;
}
}
}
}
@@ -5830,8 +60
0
3,8 @@ dp_netdev_run_meter(struct dp_netdev *dp, struct dp_packet_batch *packets_,
@@ -5830,8 +60
1
3,8 @@ dp_netdev_run_meter(struct dp_netdev *dp, struct dp_packet_batch *packets_,
/* Update the exceeding band for the exceeding packet.
/* Update the exceeding band for the exceeding packet.
* (Only one band will be fired by a packet, and that
* (Only one band will be fired by a packet, and that
* can be different for each packet.) */
* can be different for each packet.) */
...
@@ -81386,7 +81578,7 @@ index d393aab5e3..2fb0d418b1 100644
...
@@ -81386,7 +81578,7 @@ index d393aab5e3..2fb0d418b1 100644
exceeded_band[i] = m;
exceeded_band[i] = m;
}
}
}
}
@@ -5913,16 +60
8
6,14 @@ dpif_netdev_meter_set(struct dpif *dpif, ofproto_meter_id meter_id,
@@ -5913,16 +60
9
6,14 @@ dpif_netdev_meter_set(struct dpif *dpif, ofproto_meter_id meter_id,
config->bands[i].burst_size = config->bands[i].rate;
config->bands[i].burst_size = config->bands[i].rate;
}
}
...
@@ -81408,7 +81600,7 @@ index d393aab5e3..2fb0d418b1 100644
...
@@ -81408,7 +81600,7 @@ index d393aab5e3..2fb0d418b1 100644
if (band_max_delta_t > meter->max_delta_t) {
if (band_max_delta_t > meter->max_delta_t) {
meter->max_delta_t = band_max_delta_t;
meter->max_delta_t = band_max_delta_t;
}
}
@@ -7800,6 +79
7
1,7 @@ const struct dpif_class dpif_netdev_class = {
@@ -7800,6 +79
8
1,7 @@ const struct dpif_class dpif_netdev_class = {
NULL, /* ct_timeout_policy_dump_next */
NULL, /* ct_timeout_policy_dump_next */
NULL, /* ct_timeout_policy_dump_done */
NULL, /* ct_timeout_policy_dump_done */
NULL, /* ct_get_timeout_policy_name */
NULL, /* ct_get_timeout_policy_name */
...
@@ -81416,7 +81608,7 @@ index d393aab5e3..2fb0d418b1 100644
...
@@ -81416,7 +81608,7 @@ index d393aab5e3..2fb0d418b1 100644
dpif_netdev_ipf_set_enabled,
dpif_netdev_ipf_set_enabled,
dpif_netdev_ipf_set_min_frag,
dpif_netdev_ipf_set_min_frag,
dpif_netdev_ipf_set_max_nfrags,
dpif_netdev_ipf_set_max_nfrags,
@@ -8040,6 +82
1
2,7 @@ dp_netdev_pmd_try_optimize(struct dp_netdev_pmd_thread *pmd,
@@ -8040,6 +82
2
2,7 @@ dp_netdev_pmd_try_optimize(struct dp_netdev_pmd_thread *pmd,
if (pmd->ctx.now > pmd->rxq_next_cycle_store) {
if (pmd->ctx.now > pmd->rxq_next_cycle_store) {
uint64_t curr_tsc;
uint64_t curr_tsc;
...
@@ -81424,7 +81616,7 @@ index d393aab5e3..2fb0d418b1 100644
...
@@ -81424,7 +81616,7 @@ index d393aab5e3..2fb0d418b1 100644
struct pmd_auto_lb *pmd_alb = &pmd->dp->pmd_alb;
struct pmd_auto_lb *pmd_alb = &pmd->dp->pmd_alb;
if (pmd_alb->is_enabled && !pmd->isolated
if (pmd_alb->is_enabled && !pmd->isolated
&& (pmd->perf_stats.counters.n[PMD_CYCLES_ITER_IDLE] >=
&& (pmd->perf_stats.counters.n[PMD_CYCLES_ITER_IDLE] >=
@@ -8056,7 +82
2
9,9 @@ dp_netdev_pmd_try_optimize(struct dp_netdev_pmd_thread *pmd,
@@ -8056,7 +82
3
9,9 @@ dp_netdev_pmd_try_optimize(struct dp_netdev_pmd_thread *pmd,
pmd_load = ((tot_proc * 100) / (tot_idle + tot_proc));
pmd_load = ((tot_proc * 100) / (tot_idle + tot_proc));
}
}
...
@@ -81654,7 +81846,7 @@ index 45bb96b543..353d5cd3ed 100644
...
@@ -81654,7 +81846,7 @@ index 45bb96b543..353d5cd3ed 100644
}
}
diff --git a/lib/ipf.c b/lib/ipf.c
diff --git a/lib/ipf.c b/lib/ipf.c
index 446e89d13c..
24325a638d
100644
index 446e89d13c..
009f5d1e9b
100644
--- a/lib/ipf.c
--- a/lib/ipf.c
+++ b/lib/ipf.c
+++ b/lib/ipf.c
@@ -93,7 +93,6 @@ struct ipf_frag {
@@ -93,7 +93,6 @@ struct ipf_frag {
...
@@ -81706,7 +81898,7 @@ index 446e89d13c..24325a638d 100644
...
@@ -81706,7 +81898,7 @@ index 446e89d13c..24325a638d 100644
}
}
/* Filters out fragments from a batch of fragments and adjust the batch. */
/* Filters out fragments from a batch of fragments and adjust the batch. */
@@ -942,
8
+938,
7
@@ ipf_extract_frags_from_batch(struct ipf *ipf, struct dp_packet_batch *pb,
@@ -942,
9
+938,
10
@@ ipf_extract_frags_from_batch(struct ipf *ipf, struct dp_packet_batch *pb,
ipf_is_valid_v6_frag(ipf, pkt)))) {
ipf_is_valid_v6_frag(ipf, pkt)))) {
ovs_mutex_lock(&ipf->ipf_lock);
ovs_mutex_lock(&ipf->ipf_lock);
...
@@ -81714,9 +81906,12 @@ index 446e89d13c..24325a638d 100644
...
@@ -81714,9 +81906,12 @@ index 446e89d13c..24325a638d 100644
- pb->do_not_steal)) {
- pb->do_not_steal)) {
+ if (!ipf_handle_frag(ipf, pkt, dl_type, zone, now, hash_basis)) {
+ if (!ipf_handle_frag(ipf, pkt, dl_type, zone, now, hash_basis)) {
dp_packet_batch_refill(pb, pkt, pb_idx);
dp_packet_batch_refill(pb, pkt, pb_idx);
+ } else {
+ dp_packet_delete(pkt);
}
}
ovs_mutex_unlock(&ipf->ipf_lock);
ovs_mutex_unlock(&ipf->ipf_lock);
@@ -1153,59 +1148,64 @@ ipf_post_execute_reass_pkts(struct ipf *ipf,
} else {
@@ -1153,59 +1150,64 @@ ipf_post_execute_reass_pkts(struct ipf *ipf,
/* Inner batch loop is constant time since batch size is <=
/* Inner batch loop is constant time since batch size is <=
* NETDEV_MAX_BURST. */
* NETDEV_MAX_BURST. */
DP_PACKET_BATCH_REFILL_FOR_EACH (pb_idx, pb_cnt, pkt, pb) {
DP_PACKET_BATCH_REFILL_FOR_EACH (pb_idx, pb_cnt, pkt, pb) {
...
@@ -81820,7 +82015,7 @@ index 446e89d13c..24325a638d 100644
...
@@ -81820,7 +82015,7 @@ index 446e89d13c..24325a638d 100644
} else {
} else {
dp_packet_batch_refill(pb, pkt, pb_idx);
dp_packet_batch_refill(pb, pkt, pb_idx);
}
}
@@ -1337,9 +133
7
,7 @@ ipf_destroy(struct ipf *ipf)
@@ -1337,9 +133
9
,7 @@ ipf_destroy(struct ipf *ipf)
while (ipf_list->last_sent_idx < ipf_list->last_inuse_idx) {
while (ipf_list->last_sent_idx < ipf_list->last_inuse_idx) {
struct dp_packet *pkt
struct dp_packet *pkt
= ipf_list->frag_list[ipf_list->last_sent_idx + 1].pkt;
= ipf_list->frag_list[ipf_list->last_sent_idx + 1].pkt;
...
@@ -82175,10 +82370,30 @@ index 19e9305266..34738535db 100644
...
@@ -82175,10 +82370,30 @@ index 19e9305266..34738535db 100644
}
}
chassis->c_protocol = port->p_protocol = cfg->g_protocols[i].mode;
chassis->c_protocol = port->p_protocol = cfg->g_protocols[i].mode;
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
index 8b62e6d968..8
0063b933d
100644
index 8b62e6d968..8
a48a41197
100644
--- a/lib/meta-flow.c
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -2296,12 +2296,6 @@ mf_set(const struct mf_field *mf,
@@ -1764,6 +1764,19 @@ mf_is_tun_metadata(const struct mf_field *mf)
mf->id < MFF_TUN_METADATA0 + TUN_METADATA_NUM_OPTS;
}
+bool
+mf_is_frozen_metadata(const struct mf_field *mf)
+{
+ if (mf->id >= MFF_TUN_ID && mf->id <= MFF_IN_PORT_OXM) {
+ return true;
+ }
+
+ if (mf->id >= MFF_REG0 && mf->id < MFF_ETH_SRC) {
+ return true;
+ }
+ return false;
+}
+
bool
mf_is_pipeline_field(const struct mf_field *mf)
{
@@ -2296,12 +2309,6 @@ mf_set(const struct mf_field *mf,
switch (mf->id) {
switch (mf->id) {
case MFF_CT_ZONE:
case MFF_CT_ZONE:
case MFF_CT_NW_PROTO:
case MFF_CT_NW_PROTO:
...
@@ -82191,7 +82406,7 @@ index 8b62e6d968..80063b933d 100644
...
@@ -82191,7 +82406,7 @@ index 8b62e6d968..80063b933d 100644
case MFF_RECIRC_ID:
case MFF_RECIRC_ID:
case MFF_PACKET_TYPE:
case MFF_PACKET_TYPE:
case MFF_CONJ_ID:
case MFF_CONJ_ID:
@@ -2419,6 +24
13
,30 @@ mf_set(const struct mf_field *mf,
@@ -2419,6 +24
26
,30 @@ mf_set(const struct mf_field *mf,
ntoh128(mask->be128));
ntoh128(mask->be128));
break;
break;
...
@@ -85237,7 +85452,7 @@ index 409286ab15..cb197e9010 100644
...
@@ -85237,7 +85452,7 @@ index 409286ab15..cb197e9010 100644
ofproto_dpif_send_async_msg(upcall->ofproto, am);
ofproto_dpif_send_async_msg(upcall->ofproto, am);
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 4407f9c97a..
04a75e12d3
100644
index 4407f9c97a..
72c0a0efce
100644
--- a/ofproto/ofproto-dpif-xlate.c
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -1516,15 +1516,32 @@ xlate_lookup_ofproto_(const struct dpif_backer *backer,
@@ -1516,15 +1516,32 @@ xlate_lookup_ofproto_(const struct dpif_backer *backer,
...
@@ -85312,7 +85527,55 @@ index 4407f9c97a..04a75e12d3 100644
...
@@ -85312,7 +85527,55 @@ index 4407f9c97a..04a75e12d3 100644
}
}
static void
static void
@@ -7519,7 +7536,8 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
@@ -6123,11 +6140,32 @@ static void
compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc,
bool is_last_action)
{
- ovs_u128 old_ct_label_mask = ctx->wc->masks.ct_label;
- uint32_t old_ct_mark_mask = ctx->wc->masks.ct_mark;
- size_t ct_offset;
uint16_t zone;
+ if (ofc->zone_src.field) {
+ union mf_subvalue value;
+ memset(&value, 0xff, sizeof(value));
+
+ zone = mf_get_subfield(&ofc->zone_src, &ctx->xin->flow);
+ if (ctx->xin->frozen_state) {
+ /* If the upcall is a resume of a recirculation, we only need to
+ * unwildcard the fields that are not in the frozen_metadata, as
+ * when the rules update, OVS will generate a new recirc_id,
+ * which will invalidate the megaflow with old the recirc_id.
+ */
+ if (!mf_is_frozen_metadata(ofc->zone_src.field)) {
+ mf_write_subfield_flow(&ofc->zone_src, &value,
+ &ctx->wc->masks);
+ }
+ } else {
+ mf_write_subfield_flow(&ofc->zone_src, &value, &ctx->wc->masks);
+ }
+ } else {
+ zone = ofc->zone_imm;
+ }
+ size_t ct_offset;
+ ovs_u128 old_ct_label_mask = ctx->wc->masks.ct_label;
+ uint32_t old_ct_mark_mask = ctx->wc->masks.ct_mark;
/* Ensure that any prior actions are applied before composing the new
* conntrack action. */
xlate_commit_actions(ctx);
@@ -6139,11 +6177,6 @@ compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc,
do_xlate_actions(ofc->actions, ofpact_ct_get_action_len(ofc), ctx,
is_last_action, false);
- if (ofc->zone_src.field) {
- zone = mf_get_subfield(&ofc->zone_src, &ctx->xin->flow);
- } else {
- zone = ofc->zone_imm;
- }
ct_offset = nl_msg_start_nested(ctx->odp_actions, OVS_ACTION_ATTR_CT);
if (ofc->flags & NX_CT_F_COMMIT) {
@@ -7519,7 +7552,8 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
/* Restore pipeline metadata. May change flow's in_port and other
/* Restore pipeline metadata. May change flow's in_port and other
* metadata to the values that existed when freezing was triggered. */
* metadata to the values that existed when freezing was triggered. */
...
@@ -85322,7 +85585,7 @@ index 4407f9c97a..04a75e12d3 100644
...
@@ -85322,7 +85585,7 @@ index 4407f9c97a..04a75e12d3 100644
/* Restore stack, if any. */
/* Restore stack, if any. */
if (state->stack) {
if (state->stack) {
@@ -7571,14 +7
589
,10 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
@@ -7571,14 +7
605
,10 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
ctx.error = XLATE_INVALID_TUNNEL_METADATA;
ctx.error = XLATE_INVALID_TUNNEL_METADATA;
goto exit;
goto exit;
}
}
...
@@ -89688,7 +89951,7 @@ index 0000000000..1714273e35
...
@@ -89688,7 +89951,7 @@ index 0000000000..1714273e35
+OVS_TRAFFIC_VSWITCHD_STOP
+OVS_TRAFFIC_VSWITCHD_STOP
+AT_CLEANUP
+AT_CLEANUP
diff --git a/tests/system-traffic.at b/tests/system-traffic.at
diff --git a/tests/system-traffic.at b/tests/system-traffic.at
index 4a39c929c2..
620cd2512f
100644
index 4a39c929c2..
b5097f2ac3
100644
--- a/tests/system-traffic.at
--- a/tests/system-traffic.at
+++ b/tests/system-traffic.at
+++ b/tests/system-traffic.at
@@ -574,6 +574,60 @@ NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -w 2 10.1.1.100 | FORMAT_PI
@@ -574,6 +574,60 @@ NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -w 2 10.1.1.100 | FORMAT_PI
...
@@ -89769,7 +90032,119 @@ index 4a39c929c2..620cd2512f 100644
...
@@ -89769,7 +90032,119 @@ index 4a39c929c2..620cd2512f 100644
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
OVS_TRAFFIC_VSWITCHD_STOP
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP
AT_CLEANUP
@@ -2331,6 +2395,35 @@ NXST_FLOW reply:
@@ -1925,6 +1989,111 @@ tcp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=<cleared>,dport=<cleared>),reply=(src=
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP
+AT_SETUP([conntrack - zones from other field])
+CHECK_CONNTRACK()
+OVS_TRAFFIC_VSWITCHD_START()
+
+ADD_NAMESPACES(at_ns0, at_ns1)
+
+ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
+ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
+
+dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
+AT_DATA([flows.txt], [dnl
+priority=1,action=drop
+priority=10,arp,action=normal
+priority=10,icmp,action=normal
+priority=100,in_port=1,tcp,ct_state=-trk,action=ct(zone=5,table=0)
+priority=100,in_port=1,tcp,ct_state=+trk,action=ct(commit,zone=NXM_NX_CT_ZONE[]),2
+priority=100,in_port=2,ct_state=-trk,tcp,action=ct(table=0,zone=5)
+priority=100,in_port=2,ct_state=+trk,ct_zone=5,tcp,action=1
+])
+
+AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
+
+OVS_START_L7([at_ns1], [http])
+
+dnl HTTP requests from p0->p1 should work fine.
+NS_CHECK_EXEC([at_ns0], [wget 10.1.1.2 -t 3 -T 1 --retry-connrefused -v -o wget0.log])
+
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
+tcp,dnl
+orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),dnl
+reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),dnl
+zone=5,protoinfo=(state=<cleared>)
+])
+
+dnl This is to test when the zoneid is set by a field variable like
+dnl NXM_NX_CT_ZONE, the OVS xlate should generate a megaflow with a form of
+dnl "ct_zone(5), ... actions: ct(commit, zone=5)". The match "ct_zone(5)"
+dnl is needed as if we changes the zoneid into 15 in the following, the old
+dnl "ct_zone(5), ... actions: ct(commit, zone=5)" megaflow will not get hit,
+dnl and OVS will generate a new megaflow with the match "ct_zone(0xf)".
+dnl This will make sure that the new packets are committing to zoneid 15
+dnl rather than old 5.
+AT_CHECK([ovs-appctl dpctl/dump-flows --names filter=in_port=ovs-p0 dnl
+ | grep "+trk" | grep -q "ct_zone(0x5)" ], [0], [])
+
+AT_CHECK([ovs-ofctl mod-flows br0 dnl
+ 'priority=100,ct_state=-trk,tcp,in_port="ovs-p0" actions=ct(table=0,zone=15)'])
+
+NS_CHECK_EXEC([at_ns0], [wget 10.1.1.2 -t 3 -T 1 --retry-connrefused -v -o wget0.log])
+
+AT_CHECK([ovs-appctl dpctl/dump-flows --names filter=in_port=ovs-p0 dnl
+ | grep "+trk" | grep -q "ct_zone(0xf)" ], [0], [])
+
+OVS_TRAFFIC_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([conntrack - zones from other field, more tests])
+CHECK_CONNTRACK()
+OVS_TRAFFIC_VSWITCHD_START()
+
+ADD_NAMESPACES(at_ns0, at_ns1)
+
+ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
+ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
+
+dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0.
+AT_DATA([flows.txt], [dnl
+priority=1,action=drop
+priority=10,arp,action=normal
+priority=10,icmp,action=normal
+priority=100,in_port=1,tcp,ct_state=-trk,action=ct(zone=5,table=0,commit,exec(load:0xffff0005->NXM_NX_CT_LABEL[[0..31]]))
+priority=100,in_port=1,tcp,ct_state=+trk,action=ct(commit,zone=NXM_NX_CT_LABEL[[0..15]]),2
+priority=100,in_port=2,ct_state=-trk,tcp,action=ct(table=0,zone=5)
+priority=100,in_port=2,ct_state=+trk,ct_zone=5,tcp,action=1
+])
+
+AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
+
+OVS_START_L7([at_ns1], [http])
+
+dnl HTTP requests from p0->p1 should work fine.
+NS_CHECK_EXEC([at_ns0], [wget 10.1.1.2 -t 3 -T 1 --retry-connrefused -v -o wget0.log])
+
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
+tcp,dnl
+orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),dnl
+reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>),dnl
+zone=5,labels=0xffff0005,protoinfo=(state=<cleared>)
+])
+
+AT_CHECK([ovs-appctl dpctl/dump-flows --names filter=in_port=ovs-p0 dnl
+ | grep "+trk" | sed 's/0xffff0005\/0xffff/0x5\/0xffff/' dnl
+ | grep -q "ct_label(0x5/0xffff)" ], [0], [])
+
+AT_CHECK([ovs-ofctl mod-flows br0 'priority=100,ct_state=-trk,tcp,in_port="ovs-p0" actions=ct(table=0,zone=15,commit,exec(load:0xffff000f->NXM_NX_CT_LABEL[[0..31]]))'])
+
+NS_CHECK_EXEC([at_ns0], [wget 10.1.1.2 -t 3 -T 1 --retry-connrefused -v -o wget0.log])
+
+AT_CHECK([ovs-appctl dpctl/dump-flows --names filter=in_port=ovs-p0 dnl
+ | grep "+trk" | sed 's/0xffff000f\/0xffff/0xf\/0xffff/' dnl
+ | grep -q "ct_label(0xf/0xffff)" ], [0], [])
+
+OVS_TRAFFIC_VSWITCHD_STOP
+AT_CLEANUP
+
AT_SETUP([conntrack - multiple bridges])
CHECK_CONNTRACK()
OVS_TRAFFIC_VSWITCHD_START(
@@ -2331,6 +2500,35 @@ NXST_FLOW reply:
OVS_TRAFFIC_VSWITCHD_STOP
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP
AT_CLEANUP
...
@@ -89805,7 +90180,7 @@ index 4a39c929c2..620cd2512f 100644
...
@@ -89805,7 +90180,7 @@ index 4a39c929c2..620cd2512f 100644
AT_SETUP([conntrack - ICMP related])
AT_SETUP([conntrack - ICMP related])
AT_SKIP_IF([test $HAVE_NC = no])
AT_SKIP_IF([test $HAVE_NC = no])
CHECK_CONNTRACK()
CHECK_CONNTRACK()
@@ -3220,6 +3
313
,46 @@ NS_CHECK_EXEC([at_ns0], [ping6 -s 3200 -q -c 3 -i 0.3 -w 2 fc00::2 | FORMAT_PING
@@ -3220,6 +3
418
,46 @@ NS_CHECK_EXEC([at_ns0], [ping6 -s 3200 -q -c 3 -i 0.3 -w 2 fc00::2 | FORMAT_PING
OVS_TRAFFIC_VSWITCHD_STOP
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP
AT_CLEANUP
...
@@ -89852,7 +90227,7 @@ index 4a39c929c2..620cd2512f 100644
...
@@ -89852,7 +90227,7 @@ index 4a39c929c2..620cd2512f 100644
AT_SETUP([conntrack - resubmit to ct multiple times])
AT_SETUP([conntrack - resubmit to ct multiple times])
CHECK_CONNTRACK()
CHECK_CONNTRACK()
@@ -4379,6 +4
512
,52 @@ tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=
@@ -4379,6 +4
617
,52 @@ tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=
OVS_TRAFFIC_VSWITCHD_STOP
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP
AT_CLEANUP
...
@@ -89905,7 +90280,7 @@ index 4a39c929c2..620cd2512f 100644
...
@@ -89905,7 +90280,7 @@ index 4a39c929c2..620cd2512f 100644
AT_SETUP([conntrack - simple DNAT])
AT_SETUP([conntrack - simple DNAT])
CHECK_CONNTRACK()
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
CHECK_CONNTRACK_NAT()
@@ -4434,6 +4
613
,41 @@ tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=
@@ -4434,6 +4
718
,41 @@ tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=
OVS_TRAFFIC_VSWITCHD_STOP
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP
AT_CLEANUP
...
@@ -89947,7 +90322,7 @@ index 4a39c929c2..620cd2512f 100644
...
@@ -89947,7 +90322,7 @@ index 4a39c929c2..620cd2512f 100644
AT_SETUP([conntrack - more complex DNAT])
AT_SETUP([conntrack - more complex DNAT])
CHECK_CONNTRACK()
CHECK_CONNTRACK()
CHECK_CONNTRACK_NAT()
CHECK_CONNTRACK_NAT()
@@ -5873,6 +6
087
,50 @@ ovs-appctl dpif/dump-flows br0
@@ -5873,6 +6
192
,50 @@ ovs-appctl dpif/dump-flows br0
OVS_TRAFFIC_VSWITCHD_STOP
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP
AT_CLEANUP
...
@@ -91089,10 +91464,10 @@ index 4af44200e8..68ce2c5442 100644
...
@@ -91089,10 +91464,10 @@ index 4af44200e8..68ce2c5442 100644
return (error || !stream) ? 1 : 0;
return (error || !stream) ? 1 : 0;
}
}
diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at
diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at
index b92c23fde8..
9feb1c5fec
100644
index b92c23fde8..
320ae5c9c2
100644
--- a/tests/tunnel-push-pop.at
--- a/tests/tunnel-push-pop.at
+++ b/tests/tunnel-push-pop.at
+++ b/tests/tunnel-push-pop.at
@@ -573,6 +573,6
2
@@ OVS_WAIT_UNTIL([test `ovs-pcap p0.pcap | grep 50540000000a5054000000091235 | wc
@@ -573,6 +573,6
4
@@ OVS_WAIT_UNTIL([test `ovs-pcap p0.pcap | grep 50540000000a5054000000091235 | wc
OVS_VSWITCHD_STOP
OVS_VSWITCHD_STOP
AT_CLEANUP
AT_CLEANUP
...
@@ -91129,20 +91504,22 @@ index b92c23fde8..9feb1c5fec 100644
...
@@ -91129,20 +91504,22 @@ index b92c23fde8..9feb1c5fec 100644
+AT_CHECK([ovs-vsctl -- set Interface p0 options:tx_pcap=p0.pcap])
+AT_CHECK([ovs-vsctl -- set Interface p0 options:tx_pcap=p0.pcap])
+
+
+packet=50540000000a505400000009123
+packet=50540000000a505400000009123
+encap=f8bc124434b6aa55aa5500000800450000320000400040113406010102580101025c83a917c1001e00000000655800007b00
+dnl Source port is based on a packet hash, so it may differ depending on the
+dnl compiler flags and CPU type. Masked with '....'.
+encap=f8bc124434b6aa55aa5500000800450000320000400040113406010102580101025c....17c1001e00000000655800007b00
+
+
+dnl Output to tunnel from a int-br internal port.
+dnl Output to tunnel from a int-br internal port.
+dnl Checking that the packet arrived and it was correctly encapsulated.
+dnl Checking that the packet arrived and it was correctly encapsulated.
+AT_CHECK([ovs-ofctl add-flow int-br "in_port=LOCAL,actions=debug_slow,output:2"])
+AT_CHECK([ovs-ofctl add-flow int-br "in_port=LOCAL,actions=debug_slow,output:2"])
+AT_CHECK([ovs-appctl netdev-dummy/receive int-br "${packet}4"])
+AT_CHECK([ovs-appctl netdev-dummy/receive int-br "${packet}4"])
+OVS_WAIT_UNTIL([test `ovs-pcap p0.pcap | grep "${encap}${packet}4" | wc -l` -ge 1])
+OVS_WAIT_UNTIL([test `ovs-pcap p0.pcap |
e
grep "${encap}${packet}4" | wc -l` -ge 1])
+dnl Sending again to exercise the non-miss upcall path.
+dnl Sending again to exercise the non-miss upcall path.
+AT_CHECK([ovs-appctl netdev-dummy/receive int-br "${packet}4"])
+AT_CHECK([ovs-appctl netdev-dummy/receive int-br "${packet}4"])
+OVS_WAIT_UNTIL([test `ovs-pcap p0.pcap | grep "${encap}${packet}4" | wc -l` -ge 2])
+OVS_WAIT_UNTIL([test `ovs-pcap p0.pcap |
e
grep "${encap}${packet}4" | wc -l` -ge 2])
+
+
+dnl Output to tunnel from the controller.
+dnl Output to tunnel from the controller.
+AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out int-br CONTROLLER "debug_slow,output:2" "${packet}5"])
+AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out int-br CONTROLLER "debug_slow,output:2" "${packet}5"])
+OVS_WAIT_UNTIL([test `ovs-pcap p0.pcap | grep "${encap}${packet}5" | wc -l` -ge 1])
+OVS_WAIT_UNTIL([test `ovs-pcap p0.pcap |
e
grep "${encap}${packet}5" | wc -l` -ge 1])
+
+
+dnl Datapath actions should not have tunnel push action.
+dnl Datapath actions should not have tunnel push action.
+AT_CHECK([ovs-appctl dpctl/dump-flows | grep -q tnl_push], [1])
+AT_CHECK([ovs-appctl dpctl/dump-flows | grep -q tnl_push], [1])
This diff is collapsed.
Click to expand it.
SPECS/openvswitch2.13.spec
+
32
−
1
View file @
3bede4e8
...
@@ -59,7 +59,7 @@ Summary: Open vSwitch
...
@@ -59,7 +59,7 @@ Summary: Open vSwitch
Group: System Environment/Daemons daemon/database/utilities
Group: System Environment/Daemons daemon/database/utilities
URL: http://www.openvswitch.org/
URL: http://www.openvswitch.org/
Version: 2.13.0
Version: 2.13.0
Release: 12
7
%{?commit0:.%{date}git%{shortcommit0}}%{?commit1:dpdk%{shortcommit1}}%{?dist}
Release: 1
3
2%{?commit0:.%{date}git%{shortcommit0}}%{?commit1:dpdk%{shortcommit1}}%{?dist}
# Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the
# Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the
# lib/sflow*.[ch] files are SISSL
# lib/sflow*.[ch] files are SISSL
...
@@ -712,6 +712,37 @@ exit 0
...
@@ -712,6 +712,37 @@ exit 0
%endif
%endif
%changelog
%changelog
* Tue Oct 19 2021 Open vSwitch CI <ovs-ci@redhat.com> - 2.13.0-132
- Merging upstream branch-2.13 [RH git: 60a72ee3f6]
Commit list:
5c33e4db80 datapath-windows: add layers when adding the deferred actions
* Thu Oct 14 2021 Open vSwitch CI <ovs-ci@redhat.com> - 2.13.0-131
- Merging upstream branch-2.13 [RH git: 31c65d3e94]
Commit list:
6e2e180851 ofproto-dpif-xlate: Fix zone set from non-frozen-metadata fields.
* Wed Oct 13 2021 Open vSwitch CI <ovs-ci@redhat.com> - 2.13.0-130
- Merging upstream branch-2.13 [RH git: beb8cdaec6]
Commit list:
ceb395773d dpif-netdev: Fix use-after-free on PACKET_OUT of IP fragments.
fed4df9bb7 tunnel-push-pop.at: Mask source port in tunnel header.
* Tue Oct 12 2021 Open vSwitch CI <ovs-ci@redhat.com> - 2.13.0-129
- Merging upstream branch-2.13 [RH git: fc819dabd3]
Commit list:
ec44c50cf0 ipf: release unhandled packets from the batch
* Thu Sep 30 2021 Open vSwitch CI <ovs-ci@redhat.com> - 2.13.0-128
- Merging upstream branch-2.13 [RH git: 9d83aff7e3]
Commit list:
695d25f507 datapath-windows:adjust Offset when processing packet in POP_VLAN action
* Mon Sep 27 2021 Open vSwitch CI <ovs-ci@redhat.com> - 2.13.0-127
* Mon Sep 27 2021 Open vSwitch CI <ovs-ci@redhat.com> - 2.13.0-127
- Merging upstream branch-2.13 [RH git: a117849d24]
- Merging upstream branch-2.13 [RH git: a117849d24]
Commit list:
Commit list:
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment