2 * Copyright (c) 2014 VMware, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
22 #include "PacketParser.h"
28 #define OVS_DBG_MOD OVS_DBG_FLOW
31 #pragma warning( push )
32 #pragma warning( disable:4127 )
34 extern POVS_SWITCH_CONTEXT gOvsSwitchContext
;
35 extern UINT64 ovsTimeIncrementPerTick
;
37 static NTSTATUS
ReportFlowInfo(OvsFlow
*flow
, UINT32 getFlags
,
39 static NTSTATUS
HandleFlowPut(OvsFlowPut
*put
,
40 OVS_DATAPATH
*datapath
,
41 struct OvsFlowStats
*stats
);
42 static NTSTATUS
OvsPrepareFlow(OvsFlow
**flow
, const OvsFlowPut
*put
,
44 static VOID
RemoveFlow(OVS_DATAPATH
*datapath
, OvsFlow
**flow
);
45 static VOID
DeleteAllFlows(OVS_DATAPATH
*datapath
);
46 static NTSTATUS
AddFlow(OVS_DATAPATH
*datapath
, OvsFlow
*flow
);
47 static VOID
FreeFlow(OvsFlow
*flow
);
48 static VOID __inline
*GetStartAddrNBL(const NET_BUFFER_LIST
*_pNB
);
49 static NTSTATUS
_MapNlToFlowPut(POVS_MESSAGE msgIn
, PNL_ATTR keyAttr
,
51 PNL_ATTR flowAttrClear
,
52 OvsFlowPut
*mappedFlow
);
53 static VOID
_MapKeyAttrToFlowPut(PNL_ATTR
*keyAttrs
,
54 PNL_ATTR
*tunnelAttrs
,
57 static VOID
_MapTunAttrToFlowPut(PNL_ATTR
*keyAttrs
,
58 PNL_ATTR
*tunnelAttrs
,
60 static VOID
_MapNlToFlowPutFlags(PGENL_MSG_HDR genlMsgHdr
,
61 PNL_ATTR flowAttrClear
,
62 OvsFlowPut
*mappedFlow
);
64 static NTSTATUS
_FlowNlGetCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
66 static NTSTATUS
_FlowNlDumpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
68 static NTSTATUS
_MapFlowInfoToNl(PNL_BUFFER nlBuf
,
69 OvsFlowInfo
*flowInfo
);
70 static NTSTATUS
_MapFlowStatsToNlStats(PNL_BUFFER nlBuf
,
71 OvsFlowStats
*flowStats
);
72 static NTSTATUS
_MapFlowActionToNlAction(PNL_BUFFER nlBuf
,
76 static NTSTATUS
_MapFlowIpv4KeyToNlKey(PNL_BUFFER nlBuf
,
77 IpKey
*ipv4FlowPutKey
);
78 static NTSTATUS
_MapFlowIpv6KeyToNlKey(PNL_BUFFER nlBuf
,
79 Ipv6Key
*ipv6FlowPutKey
,
80 Icmp6Key
*ipv6FlowPutIcmpKey
);
81 static NTSTATUS
_MapFlowArpKeyToNlKey(PNL_BUFFER nlBuf
,
82 ArpKey
*arpFlowPutKey
);
84 static NTSTATUS
OvsDoDumpFlows(OvsFlowDumpInput
*dumpInput
,
85 OvsFlowDumpOutput
*dumpOutput
,
89 #define OVS_FLOW_TABLE_SIZE 2048
90 #define OVS_FLOW_TABLE_MASK (OVS_FLOW_TABLE_SIZE -1)
91 #define HASH_BUCKET(hash) ((hash) & OVS_FLOW_TABLE_MASK)
93 /* Flow family related netlink policies */
95 /* For Parsing attributes in FLOW_* commands */
96 const NL_POLICY nlFlowPolicy
[] = {
97 [OVS_FLOW_ATTR_KEY
] = {.type
= NL_A_NESTED
, .optional
= FALSE
},
98 [OVS_FLOW_ATTR_MASK
] = {.type
= NL_A_NESTED
, .optional
= TRUE
},
99 [OVS_FLOW_ATTR_ACTIONS
] = {.type
= NL_A_NESTED
, .optional
= TRUE
},
100 [OVS_FLOW_ATTR_STATS
] = {.type
= NL_A_UNSPEC
,
101 .minLen
= sizeof(struct ovs_flow_stats
),
102 .maxLen
= sizeof(struct ovs_flow_stats
),
104 [OVS_FLOW_ATTR_TCP_FLAGS
] = {NL_A_U8
, .optional
= TRUE
},
105 [OVS_FLOW_ATTR_USED
] = {NL_A_U64
, .optional
= TRUE
},
106 [OVS_FLOW_ATTR_PROBE
] = {.type
= NL_A_FLAG
, .optional
= TRUE
}
109 /* For Parsing nested OVS_FLOW_ATTR_KEY attributes.
110 * Some of the attributes like OVS_KEY_ATTR_RECIRC_ID
111 * & OVS_KEY_ATTR_MPLS are not supported yet. */
113 const NL_POLICY nlFlowKeyPolicy
[] = {
114 [OVS_KEY_ATTR_ENCAP
] = {.type
= NL_A_VAR_LEN
, .optional
= TRUE
},
115 [OVS_KEY_ATTR_PRIORITY
] = {.type
= NL_A_UNSPEC
, .minLen
= 4,
116 .maxLen
= 4, .optional
= TRUE
},
117 [OVS_KEY_ATTR_IN_PORT
] = {.type
= NL_A_UNSPEC
, .minLen
= 4,
118 .maxLen
= 4, .optional
= FALSE
},
119 [OVS_KEY_ATTR_ETHERNET
] = {.type
= NL_A_UNSPEC
,
120 .minLen
= sizeof(struct ovs_key_ethernet
),
121 .maxLen
= sizeof(struct ovs_key_ethernet
),
123 [OVS_KEY_ATTR_VLAN
] = {.type
= NL_A_UNSPEC
, .minLen
= 2,
124 .maxLen
= 2, .optional
= TRUE
},
125 [OVS_KEY_ATTR_ETHERTYPE
] = {.type
= NL_A_UNSPEC
, .minLen
= 2,
126 .maxLen
= 2, .optional
= TRUE
},
127 [OVS_KEY_ATTR_IPV4
] = {.type
= NL_A_UNSPEC
,
128 .minLen
= sizeof(struct ovs_key_ipv4
),
129 .maxLen
= sizeof(struct ovs_key_ipv4
),
131 [OVS_KEY_ATTR_IPV6
] = {.type
= NL_A_UNSPEC
,
132 .minLen
= sizeof(struct ovs_key_ipv6
),
133 .maxLen
= sizeof(struct ovs_key_ipv6
),
135 [OVS_KEY_ATTR_TCP
] = {.type
= NL_A_UNSPEC
,
136 .minLen
= sizeof(struct ovs_key_tcp
),
137 .maxLen
= sizeof(struct ovs_key_tcp
),
139 [OVS_KEY_ATTR_UDP
] = {.type
= NL_A_UNSPEC
,
140 .minLen
= sizeof(struct ovs_key_udp
),
141 .maxLen
= sizeof(struct ovs_key_udp
),
143 [OVS_KEY_ATTR_ICMP
] = {.type
= NL_A_UNSPEC
,
144 .minLen
= sizeof(struct ovs_key_icmp
),
145 .maxLen
= sizeof(struct ovs_key_icmp
),
147 [OVS_KEY_ATTR_ICMPV6
] = {.type
= NL_A_UNSPEC
,
148 .minLen
= sizeof(struct ovs_key_icmpv6
),
149 .maxLen
= sizeof(struct ovs_key_icmpv6
),
151 [OVS_KEY_ATTR_ARP
] = {.type
= NL_A_UNSPEC
,
152 .minLen
= sizeof(struct ovs_key_arp
),
153 .maxLen
= sizeof(struct ovs_key_arp
),
155 [OVS_KEY_ATTR_ND
] = {.type
= NL_A_UNSPEC
,
156 .minLen
= sizeof(struct ovs_key_nd
),
157 .maxLen
= sizeof(struct ovs_key_nd
),
159 [OVS_KEY_ATTR_SKB_MARK
] = {.type
= NL_A_UNSPEC
, .minLen
= 4,
160 .maxLen
= 4, .optional
= TRUE
},
161 [OVS_KEY_ATTR_TUNNEL
] = {.type
= NL_A_VAR_LEN
, .optional
= TRUE
},
162 [OVS_KEY_ATTR_SCTP
] = {.type
= NL_A_UNSPEC
,
163 .minLen
= sizeof(struct ovs_key_sctp
),
164 .maxLen
= sizeof(struct ovs_key_sctp
),
166 [OVS_KEY_ATTR_TCP_FLAGS
] = {.type
= NL_A_UNSPEC
,
167 .minLen
= 2, .maxLen
= 2,
169 [OVS_KEY_ATTR_DP_HASH
] = {.type
= NL_A_UNSPEC
, .minLen
= 4,
170 .maxLen
= 4, .optional
= TRUE
},
171 [OVS_KEY_ATTR_RECIRC_ID
] = {.type
= NL_A_UNSPEC
, .minLen
= 4,
172 .maxLen
= 4, .optional
= TRUE
},
173 [OVS_KEY_ATTR_MPLS
] = {.type
= NL_A_VAR_LEN
, .optional
= TRUE
}
175 const UINT32 nlFlowKeyPolicyLen
= ARRAY_SIZE(nlFlowKeyPolicy
);
177 /* For Parsing nested OVS_KEY_ATTR_TUNNEL attributes */
178 const NL_POLICY nlFlowTunnelKeyPolicy
[] = {
179 [OVS_TUNNEL_KEY_ATTR_ID
] = {.type
= NL_A_UNSPEC
, .minLen
= 8,
180 .maxLen
= 8, .optional
= TRUE
},
181 [OVS_TUNNEL_KEY_ATTR_IPV4_SRC
] = {.type
= NL_A_UNSPEC
, .minLen
= 4,
182 .maxLen
= 4, .optional
= TRUE
},
183 [OVS_TUNNEL_KEY_ATTR_IPV4_DST
] = {.type
= NL_A_UNSPEC
, .minLen
= 4 ,
184 .maxLen
= 4, .optional
= FALSE
},
185 [OVS_TUNNEL_KEY_ATTR_TOS
] = {.type
= NL_A_UNSPEC
, .minLen
= 1,
186 .maxLen
= 1, .optional
= TRUE
},
187 [OVS_TUNNEL_KEY_ATTR_TTL
] = {.type
= NL_A_UNSPEC
, .minLen
= 1,
188 .maxLen
= 1, .optional
= TRUE
},
189 [OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT
] = {.type
= NL_A_UNSPEC
, .minLen
= 0,
190 .maxLen
= 0, .optional
= TRUE
},
191 [OVS_TUNNEL_KEY_ATTR_CSUM
] = {.type
= NL_A_UNSPEC
, .minLen
= 0,
192 .maxLen
= 0, .optional
= TRUE
},
193 [OVS_TUNNEL_KEY_ATTR_OAM
] = {.type
= NL_A_UNSPEC
, .minLen
= 0,
194 .maxLen
= 0, .optional
= TRUE
},
195 [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS
] = {.type
= NL_A_VAR_LEN
,
199 /* For Parsing nested OVS_FLOW_ATTR_ACTIONS attributes */
200 const NL_POLICY nlFlowActionPolicy
[] = {
201 [OVS_ACTION_ATTR_OUTPUT
] = {.type
= NL_A_UNSPEC
, .minLen
= sizeof(UINT32
),
202 .maxLen
= sizeof(UINT32
), .optional
= TRUE
},
203 [OVS_ACTION_ATTR_USERSPACE
] = {.type
= NL_A_VAR_LEN
, .optional
= TRUE
},
204 [OVS_ACTION_ATTR_PUSH_VLAN
] = {.type
= NL_A_UNSPEC
,
206 sizeof(struct ovs_action_push_vlan
),
208 sizeof(struct ovs_action_push_vlan
),
210 [OVS_ACTION_ATTR_POP_VLAN
] = {.type
= NL_A_UNSPEC
, .optional
= TRUE
},
211 [OVS_ACTION_ATTR_PUSH_MPLS
] = {.type
= NL_A_UNSPEC
,
213 sizeof(struct ovs_action_push_mpls
),
215 sizeof(struct ovs_action_push_mpls
),
217 [OVS_ACTION_ATTR_POP_MPLS
] = {.type
= NL_A_UNSPEC
,
218 .minLen
= sizeof(UINT16
),
219 .maxLen
= sizeof(UINT16
),
221 [OVS_ACTION_ATTR_RECIRC
] = {.type
= NL_A_UNSPEC
,
222 .minLen
= sizeof(UINT32
),
223 .maxLen
= sizeof(UINT32
),
225 [OVS_ACTION_ATTR_HASH
] = {.type
= NL_A_UNSPEC
,
226 .minLen
= sizeof(struct ovs_action_hash
),
227 .maxLen
= sizeof(struct ovs_action_hash
),
229 [OVS_ACTION_ATTR_SET
] = {.type
= NL_A_VAR_LEN
, .optional
= TRUE
},
230 [OVS_ACTION_ATTR_SAMPLE
] = {.type
= NL_A_VAR_LEN
, .optional
= TRUE
}
234 *----------------------------------------------------------------------------
235 * Netlink interface for flow commands.
236 *----------------------------------------------------------------------------
240 *----------------------------------------------------------------------------
241 * OvsFlowNewCmdHandler --
242 * Handler for OVS_FLOW_CMD_NEW/SET/DEL command.
243 * It also handles FLUSH case (DEL w/o any key in input)
244 *----------------------------------------------------------------------------
247 OvsFlowNlCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
250 NTSTATUS rc
= STATUS_SUCCESS
;
252 POVS_MESSAGE msgIn
= (POVS_MESSAGE
)usrParamsCtx
->inputBuffer
;
253 POVS_MESSAGE msgOut
= (POVS_MESSAGE
)usrParamsCtx
->outputBuffer
;
254 PNL_MSG_HDR nlMsgHdr
= &(msgIn
->nlMsg
);
255 PGENL_MSG_HDR genlMsgHdr
= &(msgIn
->genlMsg
);
256 POVS_HDR ovsHdr
= &(msgIn
->ovsHdr
);
257 PNL_ATTR flowAttrs
[__OVS_FLOW_ATTR_MAX
];
258 UINT32 attrOffset
= NLMSG_HDRLEN
+ GENL_HDRLEN
+ OVS_HDRLEN
;
259 OvsFlowPut mappedFlow
;
261 struct ovs_flow_stats replyStats
;
262 NL_ERROR nlError
= NL_ERROR_SUCCESS
;
265 RtlZeroMemory(&mappedFlow
, sizeof(OvsFlowPut
));
266 RtlZeroMemory(&stats
, sizeof(stats
));
267 RtlZeroMemory(&replyStats
, sizeof(replyStats
));
269 if (!(usrParamsCtx
->outputBuffer
)) {
270 /* No output buffer */
271 rc
= STATUS_INVALID_BUFFER_SIZE
;
275 /* Get all the top level Flow attributes */
276 if ((NlAttrParse(nlMsgHdr
, attrOffset
, NlMsgAttrsLen(nlMsgHdr
),
277 nlFlowPolicy
, ARRAY_SIZE(nlFlowPolicy
),
278 flowAttrs
, ARRAY_SIZE(flowAttrs
)))
280 OVS_LOG_ERROR("Attr Parsing failed for msg: %p",
282 rc
= STATUS_INVALID_PARAMETER
;
286 /* FLOW_DEL command w/o any key input is a flush case. */
287 if ((genlMsgHdr
->cmd
== OVS_FLOW_CMD_DEL
) &&
288 (!(flowAttrs
[OVS_FLOW_ATTR_KEY
]))) {
290 rc
= OvsFlushFlowIoctl(ovsHdr
->dp_ifindex
);
292 if (rc
== STATUS_SUCCESS
) {
293 /* XXX: refactor this code. */
294 /* So far so good. Prepare the reply for userspace */
295 NlBufInit(&nlBuf
, usrParamsCtx
->outputBuffer
,
296 usrParamsCtx
->outputLength
);
298 /* Prepare nl Msg headers */
299 ok
= NlFillOvsMsg(&nlBuf
, nlMsgHdr
->nlmsgType
, 0,
300 nlMsgHdr
->nlmsgSeq
, nlMsgHdr
->nlmsgPid
,
301 genlMsgHdr
->cmd
, OVS_FLOW_VERSION
,
304 *replyLen
= msgOut
->nlMsg
.nlmsgLen
;
306 rc
= STATUS_INVALID_BUFFER_SIZE
;
313 if (flowAttrs
[OVS_FLOW_ATTR_PROBE
]) {
314 OVS_LOG_ERROR("Attribute OVS_FLOW_ATTR_PROBE not supported");
315 nlError
= NL_ERROR_NOENT
;
319 if ((rc
= _MapNlToFlowPut(msgIn
, flowAttrs
[OVS_FLOW_ATTR_KEY
],
320 flowAttrs
[OVS_FLOW_ATTR_ACTIONS
], flowAttrs
[OVS_FLOW_ATTR_CLEAR
],
323 OVS_LOG_ERROR("Conversion to OvsFlowPut failed");
327 rc
= OvsPutFlowIoctl(&mappedFlow
, sizeof (struct OvsFlowPut
),
329 if (rc
!= STATUS_SUCCESS
) {
330 OVS_LOG_ERROR("OvsPutFlowIoctl failed.");
334 replyStats
.n_packets
= stats
.packetCount
;
335 replyStats
.n_bytes
= stats
.byteCount
;
337 /* So far so good. Prepare the reply for userspace */
338 NlBufInit(&nlBuf
, usrParamsCtx
->outputBuffer
,
339 usrParamsCtx
->outputLength
);
341 /* Prepare nl Msg headers */
342 ok
= NlFillOvsMsg(&nlBuf
, nlMsgHdr
->nlmsgType
, 0,
343 nlMsgHdr
->nlmsgSeq
, nlMsgHdr
->nlmsgPid
,
344 genlMsgHdr
->cmd
, OVS_FLOW_VERSION
,
347 rc
= STATUS_INVALID_BUFFER_SIZE
;
353 /* Append OVS_FLOW_ATTR_STATS attribute */
354 if (!NlMsgPutTailUnspec(&nlBuf
, OVS_FLOW_ATTR_STATS
,
355 (PCHAR
)(&replyStats
), sizeof(replyStats
))) {
356 OVS_LOG_ERROR("Adding OVS_FLOW_ATTR_STATS attribute failed.");
357 rc
= STATUS_INVALID_BUFFER_SIZE
;
361 msgOut
->nlMsg
.nlmsgLen
= NLMSG_ALIGN(NlBufSize(&nlBuf
));
362 *replyLen
= msgOut
->nlMsg
.nlmsgLen
;
366 if (nlError
!= NL_ERROR_SUCCESS
) {
367 POVS_MESSAGE_ERROR msgError
= (POVS_MESSAGE_ERROR
)
368 usrParamsCtx
->outputBuffer
;
369 NlBuildErrorMsg(msgIn
, msgError
, nlError
);
370 *replyLen
= msgError
->nlMsg
.nlmsgLen
;
378 *----------------------------------------------------------------------------
379 * OvsFlowNlGetCmdHandler --
380 * Handler for OVS_FLOW_CMD_GET/DUMP commands.
381 *----------------------------------------------------------------------------
384 OvsFlowNlGetCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
387 NTSTATUS status
= STATUS_SUCCESS
;
388 NL_ERROR nlError
= NL_ERROR_SUCCESS
;
389 POVS_MESSAGE msgIn
= (POVS_MESSAGE
)usrParamsCtx
->inputBuffer
;
391 if (usrParamsCtx
->devOp
== OVS_TRANSACTION_DEV_OP
) {
392 status
= _FlowNlGetCmdHandler(usrParamsCtx
, replyLen
);
394 /* No trasanctional errors as of now.
395 * If we have something then we need to convert rc to
397 if ((nlError
!= NL_ERROR_SUCCESS
) &&
398 (usrParamsCtx
->outputBuffer
)) {
399 POVS_MESSAGE_ERROR msgError
= (POVS_MESSAGE_ERROR
)
400 usrParamsCtx
->outputBuffer
;
401 NlBuildErrorMsg(msgIn
, msgError
, nlError
);
402 *replyLen
= msgError
->nlMsg
.nlmsgLen
;
403 status
= STATUS_SUCCESS
;
407 status
= _FlowNlDumpCmdHandler(usrParamsCtx
, replyLen
);
415 *----------------------------------------------------------------------------
416 * _FlowNlGetCmdHandler --
417 * Handler for OVS_FLOW_CMD_GET command.
418 *----------------------------------------------------------------------------
421 _FlowNlGetCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
424 NTSTATUS rc
= STATUS_SUCCESS
;
425 POVS_MESSAGE msgIn
= (POVS_MESSAGE
)usrParamsCtx
->inputBuffer
;
426 PNL_MSG_HDR nlMsgHdr
= &(msgIn
->nlMsg
);
427 POVS_HDR ovsHdr
= &(msgIn
->ovsHdr
);
428 PNL_MSG_HDR nlMsgOutHdr
= NULL
;
429 UINT32 attrOffset
= NLMSG_HDRLEN
+ GENL_HDRLEN
+ OVS_HDRLEN
;
430 PNL_ATTR nlAttrs
[__OVS_FLOW_ATTR_MAX
];
432 OvsFlowGetInput getInput
;
433 OvsFlowGetOutput getOutput
;
435 PNL_ATTR keyAttrs
[__OVS_KEY_ATTR_MAX
];
436 PNL_ATTR tunnelAttrs
[__OVS_TUNNEL_KEY_ATTR_MAX
];
438 NlBufInit(&nlBuf
, usrParamsCtx
->outputBuffer
,
439 usrParamsCtx
->outputLength
);
440 RtlZeroMemory(&getInput
, sizeof(OvsFlowGetInput
));
441 RtlZeroMemory(&getOutput
, sizeof(OvsFlowGetOutput
));
442 UINT32 keyAttrOffset
= 0;
443 UINT32 tunnelKeyAttrOffset
= 0;
446 if (usrParamsCtx
->inputLength
> usrParamsCtx
->outputLength
) {
447 /* Should not be the case.
448 * We'll be copying the flow keys back from
449 * input buffer to output buffer. */
450 rc
= STATUS_INVALID_PARAMETER
;
451 OVS_LOG_ERROR("inputLength: %d GREATER THEN outputLength: %d",
452 usrParamsCtx
->inputLength
, usrParamsCtx
->outputLength
);
456 /* Get all the top level Flow attributes */
457 if ((NlAttrParse(nlMsgHdr
, attrOffset
, NlMsgAttrsLen(nlMsgHdr
),
458 nlFlowPolicy
, ARRAY_SIZE(nlFlowPolicy
),
459 nlAttrs
, ARRAY_SIZE(nlAttrs
)))
461 OVS_LOG_ERROR("Attr Parsing failed for msg: %p",
463 rc
= STATUS_INVALID_PARAMETER
;
467 keyAttrOffset
= (UINT32
)((PCHAR
) nlAttrs
[OVS_FLOW_ATTR_KEY
] -
470 /* Get flow keys attributes */
471 if ((NlAttrParseNested(nlMsgHdr
, keyAttrOffset
,
472 NlAttrLen(nlAttrs
[OVS_FLOW_ATTR_KEY
]),
473 nlFlowKeyPolicy
, ARRAY_SIZE(nlFlowKeyPolicy
),
474 keyAttrs
, ARRAY_SIZE(keyAttrs
)))
476 OVS_LOG_ERROR("Key Attr Parsing failed for msg: %p",
478 rc
= STATUS_INVALID_PARAMETER
;
482 if (keyAttrs
[OVS_KEY_ATTR_TUNNEL
]) {
483 tunnelKeyAttrOffset
= (UINT32
)((PCHAR
)
484 (keyAttrs
[OVS_KEY_ATTR_TUNNEL
])
487 /* Get tunnel keys attributes */
488 if ((NlAttrParseNested(nlMsgHdr
, tunnelKeyAttrOffset
,
489 NlAttrLen(keyAttrs
[OVS_KEY_ATTR_TUNNEL
]),
490 nlFlowTunnelKeyPolicy
,
491 ARRAY_SIZE(nlFlowTunnelKeyPolicy
),
492 tunnelAttrs
, ARRAY_SIZE(tunnelAttrs
)))
494 OVS_LOG_ERROR("Tunnel key Attr Parsing failed for msg: %p",
496 rc
= STATUS_INVALID_PARAMETER
;
501 _MapKeyAttrToFlowPut(keyAttrs
, tunnelAttrs
,
504 getInput
.dpNo
= ovsHdr
->dp_ifindex
;
505 getInput
.getFlags
= FLOW_GET_STATS
| FLOW_GET_ACTIONS
;
507 /* 4th argument is a no op.
508 * We are keeping this argument to be compatible
509 * with our dpif-windows based interface. */
510 rc
= OvsGetFlowIoctl(&getInput
, &getOutput
);
511 if (rc
!= STATUS_SUCCESS
) {
512 OVS_LOG_ERROR("OvsGetFlowIoctl failed.");
516 /* Lets prepare the reply. */
517 nlMsgOutHdr
= (PNL_MSG_HDR
)(NlBufAt(&nlBuf
, 0, 0));
519 /* Input already has all the attributes for the flow key.
520 * Lets copy the values back. */
521 ok
= NlMsgPutTail(&nlBuf
, (PCHAR
)(usrParamsCtx
->inputBuffer
),
522 usrParamsCtx
->inputLength
);
524 OVS_LOG_ERROR("Could not copy the data to the buffer tail");
528 rc
= _MapFlowStatsToNlStats(&nlBuf
, &((getOutput
.info
).stats
));
529 if (rc
!= STATUS_SUCCESS
) {
530 OVS_LOG_ERROR("_OvsFlowMapFlowKeyToNlStats failed.");
534 rc
= _MapFlowActionToNlAction(&nlBuf
, ((getOutput
.info
).actionsLen
),
535 getOutput
.info
.actions
);
536 if (rc
!= STATUS_SUCCESS
) {
537 OVS_LOG_ERROR("_MapFlowActionToNlAction failed.");
541 NlMsgSetSize(nlMsgOutHdr
, NlBufSize(&nlBuf
));
542 NlMsgAlignSize(nlMsgOutHdr
);
543 *replyLen
+= NlMsgSize(nlMsgOutHdr
);
550 *----------------------------------------------------------------------------
551 * _FlowNlDumpCmdHandler --
552 * Handler for OVS_FLOW_CMD_DUMP command.
553 *----------------------------------------------------------------------------
556 _FlowNlDumpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
559 NTSTATUS rc
= STATUS_SUCCESS
;
560 UINT32 temp
= 0; /* To keep compiler happy for calling OvsDoDumpFlows */
562 POVS_OPEN_INSTANCE instance
= (POVS_OPEN_INSTANCE
)
563 (usrParamsCtx
->ovsInstance
);
565 if (usrParamsCtx
->devOp
== OVS_WRITE_DEV_OP
) {
567 OvsSetupDumpStart(usrParamsCtx
);
571 POVS_MESSAGE msgIn
= instance
->dumpState
.ovsMsg
;
572 PNL_MSG_HDR nlMsgHdr
= &(msgIn
->nlMsg
);
573 PGENL_MSG_HDR genlMsgHdr
= &(msgIn
->genlMsg
);
574 POVS_HDR ovsHdr
= &(msgIn
->ovsHdr
);
575 PNL_MSG_HDR nlMsgOutHdr
= NULL
;
576 UINT32 hdrOffset
= 0;
579 OvsFlowDumpOutput dumpOutput
;
580 OvsFlowDumpInput dumpInput
;
583 NlBufInit(&nlBuf
, usrParamsCtx
->outputBuffer
,
584 usrParamsCtx
->outputLength
);
586 ASSERT(usrParamsCtx
->devOp
== OVS_READ_DEV_OP
);
587 ASSERT(usrParamsCtx
->outputLength
);
589 RtlZeroMemory(&dumpInput
, sizeof(OvsFlowDumpInput
));
590 RtlZeroMemory(&dumpOutput
, sizeof(OvsFlowDumpOutput
));
592 dumpInput
.dpNo
= ovsHdr
->dp_ifindex
;
593 dumpInput
.getFlags
= FLOW_GET_KEY
| FLOW_GET_STATS
| FLOW_GET_ACTIONS
;
595 /* Lets provide as many flows to userspace as possible. */
597 dumpInput
.position
[0] = instance
->dumpState
.index
[0];
598 dumpInput
.position
[1] = instance
->dumpState
.index
[1];
600 rc
= OvsDoDumpFlows(&dumpInput
, &dumpOutput
, &temp
);
601 if (rc
!= STATUS_SUCCESS
) {
602 OVS_LOG_ERROR("OvsDoDumpFlows failed with rc: %d", rc
);
606 /* Done with Dump, send NLMSG_DONE */
607 if (!(dumpOutput
.n
)) {
610 OVS_LOG_INFO("Dump Done");
612 nlMsgOutHdr
= (PNL_MSG_HDR
)(NlBufAt(&nlBuf
, NlBufSize(&nlBuf
), 0));
613 ok
= NlFillNlHdr(&nlBuf
, NLMSG_DONE
, NLM_F_MULTI
,
614 nlMsgHdr
->nlmsgSeq
, nlMsgHdr
->nlmsgPid
);
617 rc
= STATUS_INVALID_BUFFER_SIZE
;
618 OVS_LOG_ERROR("Unable to prepare DUMP_DONE reply.");
624 NlMsgAlignSize(nlMsgOutHdr
);
625 *replyLen
+= NlMsgSize(nlMsgOutHdr
);
627 FreeUserDumpState(instance
);
632 hdrOffset
= NlBufSize(&nlBuf
);
633 nlMsgOutHdr
= (PNL_MSG_HDR
)(NlBufAt(&nlBuf
, hdrOffset
, 0));
636 ok
= NlFillOvsMsg(&nlBuf
, nlMsgHdr
->nlmsgType
, NLM_F_MULTI
,
637 nlMsgHdr
->nlmsgSeq
, nlMsgHdr
->nlmsgPid
,
638 genlMsgHdr
->cmd
, genlMsgHdr
->version
,
642 /* Reset rc to success so that we can
643 * send already added messages to user space. */
648 /* Time to add attributes */
649 rc
= _MapFlowInfoToNl(&nlBuf
, &(dumpOutput
.flow
));
650 if (rc
!= STATUS_SUCCESS
) {
651 /* Adding the attribute failed, we are out of
652 space in the buffer, remove the appended OVS header */
653 NlMsgSetSize(nlMsgOutHdr
,
654 NlMsgSize(nlMsgOutHdr
) -
655 sizeof(struct _OVS_MESSAGE
));
657 /* Reset rc to success so that we can
658 * send already added messages to user space. */
663 NlMsgSetSize(nlMsgOutHdr
, NlBufSize(&nlBuf
) - hdrOffset
);
664 NlMsgAlignSize(nlMsgOutHdr
);
665 *replyLen
+= NlMsgSize(nlMsgOutHdr
);
666 instance
->dumpState
.index
[0] = dumpOutput
.position
[0];
667 instance
->dumpState
.index
[1] = dumpOutput
.position
[1];
676 *----------------------------------------------------------------------------
677 * _MapFlowInfoToNl --
678 * Maps OvsFlowInfo to Netlink attributes.
679 *----------------------------------------------------------------------------
682 _MapFlowInfoToNl(PNL_BUFFER nlBuf
, OvsFlowInfo
*flowInfo
)
684 NTSTATUS rc
= STATUS_SUCCESS
;
686 rc
= MapFlowKeyToNlKey(nlBuf
, &(flowInfo
->key
), OVS_FLOW_ATTR_KEY
,
687 OVS_KEY_ATTR_TUNNEL
);
688 if (rc
!= STATUS_SUCCESS
) {
692 rc
= _MapFlowStatsToNlStats(nlBuf
, &(flowInfo
->stats
));
693 if (rc
!= STATUS_SUCCESS
) {
697 rc
= _MapFlowActionToNlAction(nlBuf
, flowInfo
->actionsLen
,
699 if (rc
!= STATUS_SUCCESS
) {
708 *----------------------------------------------------------------------------
709 * _MapFlowStatsToNlStats --
710 * Maps OvsFlowStats to OVS_FLOW_ATTR_STATS attribute.
711 *----------------------------------------------------------------------------
714 _MapFlowStatsToNlStats(PNL_BUFFER nlBuf
, OvsFlowStats
*flowStats
)
716 NTSTATUS rc
= STATUS_SUCCESS
;
717 struct ovs_flow_stats replyStats
;
719 replyStats
.n_packets
= flowStats
->packetCount
;
720 replyStats
.n_bytes
= flowStats
->byteCount
;
722 if (!NlMsgPutTailU64(nlBuf
, OVS_FLOW_ATTR_USED
, flowStats
->used
)) {
723 rc
= STATUS_INVALID_BUFFER_SIZE
;
727 if (!NlMsgPutTailUnspec(nlBuf
, OVS_FLOW_ATTR_STATS
,
728 (PCHAR
)(&replyStats
),
729 sizeof(struct ovs_flow_stats
))) {
730 rc
= STATUS_INVALID_BUFFER_SIZE
;
734 if (!NlMsgPutTailU8(nlBuf
, OVS_FLOW_ATTR_TCP_FLAGS
, flowStats
->tcpFlags
)) {
735 rc
= STATUS_INVALID_BUFFER_SIZE
;
744 *----------------------------------------------------------------------------
745 * _MapFlowActionToNlAction --
746 * Maps flow actions to OVS_FLOW_ATTR_ACTION attribute.
747 *----------------------------------------------------------------------------
750 _MapFlowActionToNlAction(PNL_BUFFER nlBuf
, uint32_t actionsLen
,
753 NTSTATUS rc
= STATUS_SUCCESS
;
756 offset
= NlMsgStartNested(nlBuf
, OVS_FLOW_ATTR_ACTIONS
);
758 /* Starting the nested attribute failed. */
759 rc
= STATUS_INVALID_BUFFER_SIZE
;
760 goto error_nested_start
;
763 if (!NlBufCopyAtTail(nlBuf
, (PCHAR
)actions
, actionsLen
)) {
764 /* Adding a nested attribute failed. */
765 rc
= STATUS_INVALID_BUFFER_SIZE
;
770 NlMsgEndNested(nlBuf
, offset
);
777 *----------------------------------------------------------------------------
778 * MapFlowKeyToNlKey --
779 * Maps OvsFlowKey to OVS_FLOW_ATTR_KEY attribute.
780 *----------------------------------------------------------------------------
783 MapFlowKeyToNlKey(PNL_BUFFER nlBuf
,
788 NTSTATUS rc
= STATUS_SUCCESS
;
789 struct ovs_key_ethernet ethKey
;
792 offset
= NlMsgStartNested(nlBuf
, keyType
);
794 /* Starting the nested attribute failed. */
795 rc
= STATUS_UNSUCCESSFUL
;
796 goto error_nested_start
;
799 /* Ethernet header */
800 RtlCopyMemory(&(ethKey
.eth_src
), flowKey
->l2
.dlSrc
, ETH_ADDR_LEN
);
801 RtlCopyMemory(&(ethKey
.eth_dst
), flowKey
->l2
.dlDst
, ETH_ADDR_LEN
);
803 if (!NlMsgPutTailUnspec(nlBuf
, OVS_KEY_ATTR_ETHERNET
,
805 sizeof(struct ovs_key_ethernet
))) {
806 rc
= STATUS_UNSUCCESSFUL
;
810 if (!NlMsgPutTailU32(nlBuf
, OVS_KEY_ATTR_IN_PORT
,
811 flowKey
->l2
.inPort
)) {
812 rc
= STATUS_UNSUCCESSFUL
;
816 if (!NlMsgPutTailU16(nlBuf
, OVS_KEY_ATTR_ETHERTYPE
,
817 flowKey
->l2
.dlType
)) {
818 rc
= STATUS_UNSUCCESSFUL
;
822 if (flowKey
->l2
.vlanTci
) {
823 if (!NlMsgPutTailU16(nlBuf
, OVS_KEY_ATTR_VLAN
,
824 flowKey
->l2
.vlanTci
)) {
825 rc
= STATUS_UNSUCCESSFUL
;
830 /* ==== L3 + L4 ==== */
831 switch (ntohs(flowKey
->l2
.dlType
)) {
832 case ETH_TYPE_IPV4
: {
833 IpKey
*ipv4FlowPutKey
= &(flowKey
->ipKey
);
834 rc
= _MapFlowIpv4KeyToNlKey(nlBuf
, ipv4FlowPutKey
);
838 case ETH_TYPE_IPV6
: {
839 Ipv6Key
*ipv6FlowPutKey
= &(flowKey
->ipv6Key
);
840 Icmp6Key
*icmpv6FlowPutKey
= &(flowKey
->icmp6Key
);
841 rc
= _MapFlowIpv6KeyToNlKey(nlBuf
, ipv6FlowPutKey
,
847 case ETH_TYPE_RARP
: {
848 ArpKey
*arpFlowPutKey
= &(flowKey
->arpKey
);
849 rc
= _MapFlowArpKeyToNlKey(nlBuf
, arpFlowPutKey
);
857 if (rc
!= STATUS_SUCCESS
) {
861 if (flowKey
->tunKey
.dst
) {
862 rc
= MapFlowTunKeyToNlKey(nlBuf
, &(flowKey
->tunKey
),
864 if (rc
!= STATUS_SUCCESS
) {
870 NlMsgEndNested(nlBuf
, offset
);
876 *----------------------------------------------------------------------------
877 * MapFlowTunKeyToNlKey --
878 * Maps OvsIPv4TunnelKey to OVS_TUNNEL_KEY_ATTR_ID attribute.
879 *----------------------------------------------------------------------------
882 MapFlowTunKeyToNlKey(PNL_BUFFER nlBuf
,
883 OvsIPv4TunnelKey
*tunKey
,
886 NTSTATUS rc
= STATUS_SUCCESS
;
889 offset
= NlMsgStartNested(nlBuf
, tunKeyType
);
891 /* Starting the nested attribute failed. */
892 rc
= STATUS_UNSUCCESSFUL
;
893 goto error_nested_start
;
896 if (!NlMsgPutTailU64(nlBuf
, OVS_TUNNEL_KEY_ATTR_ID
,
898 rc
= STATUS_UNSUCCESSFUL
;
902 if (!NlMsgPutTailU32(nlBuf
, OVS_TUNNEL_KEY_ATTR_IPV4_DST
,
904 rc
= STATUS_UNSUCCESSFUL
;
908 if (!NlMsgPutTailU32(nlBuf
, OVS_TUNNEL_KEY_ATTR_IPV4_SRC
,
910 rc
= STATUS_UNSUCCESSFUL
;
914 if (!NlMsgPutTailU8(nlBuf
, OVS_TUNNEL_KEY_ATTR_TOS
,
916 rc
= STATUS_UNSUCCESSFUL
;
920 if (!NlMsgPutTailU8(nlBuf
, OVS_TUNNEL_KEY_ATTR_TTL
,
922 rc
= STATUS_UNSUCCESSFUL
;
927 NlMsgEndNested(nlBuf
, offset
);
933 *----------------------------------------------------------------------------
934 * _MapFlowTunKeyToNlKey --
935 * Maps OvsIPv4FlowPutKey to OVS_KEY_ATTR_IPV4 attribute.
936 *----------------------------------------------------------------------------
939 _MapFlowIpv4KeyToNlKey(PNL_BUFFER nlBuf
, IpKey
*ipv4FlowPutKey
)
941 NTSTATUS rc
= STATUS_SUCCESS
;
942 struct ovs_key_ipv4 ipv4Key
;
944 ipv4Key
.ipv4_src
= ipv4FlowPutKey
->nwSrc
;
945 ipv4Key
.ipv4_dst
= ipv4FlowPutKey
->nwDst
;
946 ipv4Key
.ipv4_proto
= ipv4FlowPutKey
->nwProto
;
947 ipv4Key
.ipv4_tos
= ipv4FlowPutKey
->nwTos
;
948 ipv4Key
.ipv4_ttl
= ipv4FlowPutKey
->nwTtl
;
949 ipv4Key
.ipv4_frag
= ipv4FlowPutKey
->nwFrag
;
951 if (!NlMsgPutTailUnspec(nlBuf
, OVS_KEY_ATTR_IPV4
,
953 sizeof(struct ovs_key_ipv4
))) {
954 rc
= STATUS_UNSUCCESSFUL
;
958 switch (ipv4Key
.ipv4_proto
) {
960 struct ovs_key_tcp tcpKey
;
961 tcpKey
.tcp_src
= ipv4FlowPutKey
->l4
.tpSrc
;
962 tcpKey
.tcp_dst
= ipv4FlowPutKey
->l4
.tpDst
;
963 if (!NlMsgPutTailUnspec(nlBuf
, OVS_KEY_ATTR_TCP
,
966 rc
= STATUS_UNSUCCESSFUL
;
973 struct ovs_key_udp udpKey
;
974 udpKey
.udp_src
= ipv4FlowPutKey
->l4
.tpSrc
;
975 udpKey
.udp_dst
= ipv4FlowPutKey
->l4
.tpDst
;
976 if (!NlMsgPutTailUnspec(nlBuf
, OVS_KEY_ATTR_UDP
,
979 rc
= STATUS_UNSUCCESSFUL
;
986 struct ovs_key_sctp sctpKey
;
987 sctpKey
.sctp_src
= ipv4FlowPutKey
->l4
.tpSrc
;
988 sctpKey
.sctp_dst
= ipv4FlowPutKey
->l4
.tpDst
;
989 if (!NlMsgPutTailUnspec(nlBuf
, OVS_KEY_ATTR_SCTP
,
992 rc
= STATUS_UNSUCCESSFUL
;
999 struct ovs_key_icmp icmpKey
;
1000 /* XXX: revisit to see if htons is needed */
1001 icmpKey
.icmp_type
= (__u8
)(ipv4FlowPutKey
->l4
.tpSrc
);
1002 icmpKey
.icmp_code
= (__u8
)(ipv4FlowPutKey
->l4
.tpDst
);
1004 if (!NlMsgPutTailUnspec(nlBuf
, OVS_KEY_ATTR_ICMP
,
1007 rc
= STATUS_UNSUCCESSFUL
;
1022 *----------------------------------------------------------------------------
1023 * _MapFlowIpv6KeyToNlKey --
1024 * Maps _MapFlowIpv6KeyToNlKey to OVS_KEY_ATTR_IPV6 attribute.
1025 *----------------------------------------------------------------------------
1028 _MapFlowIpv6KeyToNlKey(PNL_BUFFER nlBuf
, Ipv6Key
*ipv6FlowPutKey
,
1029 Icmp6Key
*icmpv6FlowPutKey
)
1031 NTSTATUS rc
= STATUS_SUCCESS
;
1032 struct ovs_key_ipv6 ipv6Key
;
1034 RtlCopyMemory(&(ipv6Key
.ipv6_src
), &ipv6FlowPutKey
->ipv6Src
,
1035 sizeof ipv6Key
.ipv6_src
);
1036 RtlCopyMemory(&(ipv6Key
.ipv6_dst
), &ipv6FlowPutKey
->ipv6Dst
,
1037 sizeof ipv6Key
.ipv6_dst
);
1039 ipv6Key
.ipv6_label
= ipv6FlowPutKey
->ipv6Label
;
1040 ipv6Key
.ipv6_proto
= ipv6FlowPutKey
->nwProto
;
1041 ipv6Key
.ipv6_tclass
= ipv6FlowPutKey
->nwTos
;
1042 ipv6Key
.ipv6_hlimit
= ipv6FlowPutKey
->nwTtl
;
1043 ipv6Key
.ipv6_frag
= ipv6FlowPutKey
->nwFrag
;
1045 if (!NlMsgPutTailUnspec(nlBuf
, OVS_KEY_ATTR_IPV6
,
1048 rc
= STATUS_UNSUCCESSFUL
;
1052 switch (ipv6Key
.ipv6_proto
) {
1054 struct ovs_key_tcp tcpKey
;
1055 tcpKey
.tcp_src
= ipv6FlowPutKey
->l4
.tpSrc
;
1056 tcpKey
.tcp_dst
= ipv6FlowPutKey
->l4
.tpDst
;
1057 if (!NlMsgPutTailUnspec(nlBuf
, OVS_KEY_ATTR_TCP
,
1060 rc
= STATUS_UNSUCCESSFUL
;
1067 struct ovs_key_udp udpKey
;
1068 udpKey
.udp_src
= ipv6FlowPutKey
->l4
.tpSrc
;
1069 udpKey
.udp_dst
= ipv6FlowPutKey
->l4
.tpDst
;
1070 if (!NlMsgPutTailUnspec(nlBuf
, OVS_KEY_ATTR_UDP
,
1073 rc
= STATUS_UNSUCCESSFUL
;
1079 case IPPROTO_SCTP
: {
1080 struct ovs_key_sctp sctpKey
;
1081 sctpKey
.sctp_src
= ipv6FlowPutKey
->l4
.tpSrc
;
1082 sctpKey
.sctp_dst
= ipv6FlowPutKey
->l4
.tpDst
;
1083 if (!NlMsgPutTailUnspec(nlBuf
, OVS_KEY_ATTR_SCTP
,
1086 rc
= STATUS_UNSUCCESSFUL
;
1092 case IPPROTO_ICMPV6
: {
1093 struct ovs_key_icmpv6 icmpV6Key
;
1094 struct ovs_key_nd ndKey
;
1096 /* XXX: revisit to see if htons is needed */
1097 icmpV6Key
.icmpv6_type
= (__u8
)(icmpv6FlowPutKey
->l4
.tpSrc
);
1098 icmpV6Key
.icmpv6_code
= (__u8
)(icmpv6FlowPutKey
->l4
.tpDst
);
1100 if (!NlMsgPutTailUnspec(nlBuf
, OVS_KEY_ATTR_ICMPV6
,
1101 (PCHAR
)(&icmpV6Key
),
1102 sizeof(icmpV6Key
))) {
1103 rc
= STATUS_UNSUCCESSFUL
;
1107 RtlCopyMemory(&(ndKey
.nd_target
), &icmpv6FlowPutKey
->ndTarget
,
1108 sizeof(icmpv6FlowPutKey
->ndTarget
));
1109 RtlCopyMemory(&(ndKey
.nd_sll
), &icmpv6FlowPutKey
->arpSha
,
1111 RtlCopyMemory(&(ndKey
.nd_tll
), &icmpv6FlowPutKey
->arpTha
,
1113 if (!NlMsgPutTailUnspec(nlBuf
, OVS_KEY_ATTR_ND
,
1116 rc
= STATUS_UNSUCCESSFUL
;
1132 *----------------------------------------------------------------------------
1133 * _MapFlowArpKeyToNlKey --
1134 * Maps _MapFlowArpKeyToNlKey to OVS_KEY_ATTR_ARP attribute.
1135 *----------------------------------------------------------------------------
1138 _MapFlowArpKeyToNlKey(PNL_BUFFER nlBuf
, ArpKey
*arpFlowPutKey
)
1140 NTSTATUS rc
= STATUS_SUCCESS
;
1141 struct ovs_key_arp arpKey
;
1143 arpKey
.arp_sip
= arpFlowPutKey
->nwSrc
;
1144 arpKey
.arp_tip
= arpFlowPutKey
->nwDst
;
1146 RtlCopyMemory(&(arpKey
.arp_sha
), arpFlowPutKey
->arpSha
, ETH_ADDR_LEN
);
1147 RtlCopyMemory(&(arpKey
.arp_tha
), arpFlowPutKey
->arpTha
, ETH_ADDR_LEN
);
1150 * Flow_Extract() stores 'nwProto' in host order for ARP since 'nwProto' is
1151 * 1 byte field and the ARP opcode is 2 bytes, and all of the kernel code
1152 * understand this while looking at an ARP key.
1153 * While we pass up the ARP key to userspace, convert from host order to
1154 * network order. Likewise, when processing an ARP key from userspace,
1155 * convert from network order to host order.
1157 * It is important to note that the flow table stores the ARP opcode field
1160 arpKey
.arp_op
= htons(arpFlowPutKey
->nwProto
);
1162 if (!NlMsgPutTailUnspec(nlBuf
, OVS_KEY_ATTR_ARP
,
1165 rc
= STATUS_UNSUCCESSFUL
;
1174 *----------------------------------------------------------------------------
1175 * _MapNlToFlowPut --
1176 * Maps input netlink message to OvsFlowPut.
1177 *----------------------------------------------------------------------------
1180 _MapNlToFlowPut(POVS_MESSAGE msgIn
, PNL_ATTR keyAttr
,
1181 PNL_ATTR actionAttr
, PNL_ATTR flowAttrClear
,
1182 OvsFlowPut
*mappedFlow
)
1184 NTSTATUS rc
= STATUS_SUCCESS
;
1185 PNL_MSG_HDR nlMsgHdr
= &(msgIn
->nlMsg
);
1186 PGENL_MSG_HDR genlMsgHdr
= &(msgIn
->genlMsg
);
1187 POVS_HDR ovsHdr
= &(msgIn
->ovsHdr
);
1189 UINT32 keyAttrOffset
= (UINT32
)((PCHAR
)keyAttr
- (PCHAR
)nlMsgHdr
);
1190 UINT32 tunnelKeyAttrOffset
;
1192 PNL_ATTR keyAttrs
[__OVS_KEY_ATTR_MAX
] = {NULL
};
1193 PNL_ATTR tunnelAttrs
[__OVS_TUNNEL_KEY_ATTR_MAX
] = {NULL
};
1195 /* Get flow keys attributes */
1196 if ((NlAttrParseNested(nlMsgHdr
, keyAttrOffset
, NlAttrLen(keyAttr
),
1197 nlFlowKeyPolicy
, ARRAY_SIZE(nlFlowKeyPolicy
),
1198 keyAttrs
, ARRAY_SIZE(keyAttrs
)))
1200 OVS_LOG_ERROR("Key Attr Parsing failed for msg: %p",
1202 rc
= STATUS_INVALID_PARAMETER
;
1206 if (keyAttrs
[OVS_KEY_ATTR_TUNNEL
]) {
1207 tunnelKeyAttrOffset
= (UINT32
)((PCHAR
)
1208 (keyAttrs
[OVS_KEY_ATTR_TUNNEL
])
1211 /* Get tunnel keys attributes */
1212 if ((NlAttrParseNested(nlMsgHdr
, tunnelKeyAttrOffset
,
1213 NlAttrLen(keyAttrs
[OVS_KEY_ATTR_TUNNEL
]),
1214 nlFlowTunnelKeyPolicy
,
1215 ARRAY_SIZE(nlFlowTunnelKeyPolicy
),
1216 tunnelAttrs
, ARRAY_SIZE(tunnelAttrs
)))
1218 OVS_LOG_ERROR("Tunnel key Attr Parsing failed for msg: %p",
1220 rc
= STATUS_INVALID_PARAMETER
;
1225 _MapKeyAttrToFlowPut(keyAttrs
, tunnelAttrs
,
1226 &(mappedFlow
->key
));
1228 /* Map the action */
1230 mappedFlow
->actionsLen
= NlAttrGetSize(actionAttr
);
1231 mappedFlow
->actions
= NlAttrGet(actionAttr
);
1234 mappedFlow
->dpNo
= ovsHdr
->dp_ifindex
;
1236 _MapNlToFlowPutFlags(genlMsgHdr
, flowAttrClear
,
1244 *----------------------------------------------------------------------------
1245 * _MapNlToFlowPutFlags --
1246 * Maps netlink message to OvsFlowPut->flags.
1247 *----------------------------------------------------------------------------
1250 _MapNlToFlowPutFlags(PGENL_MSG_HDR genlMsgHdr
,
1251 PNL_ATTR flowAttrClear
, OvsFlowPut
*mappedFlow
)
1255 switch (genlMsgHdr
->cmd
) {
1256 case OVS_FLOW_CMD_NEW
:
1257 flags
|= OVSWIN_FLOW_PUT_CREATE
;
1259 case OVS_FLOW_CMD_DEL
:
1260 flags
|= OVSWIN_FLOW_PUT_DELETE
;
1262 case OVS_FLOW_CMD_SET
:
1263 flags
|= OVSWIN_FLOW_PUT_MODIFY
;
1269 if (flowAttrClear
) {
1270 flags
|= OVSWIN_FLOW_PUT_CLEAR
;
1273 mappedFlow
->flags
= flags
;
1277 *----------------------------------------------------------------------------
1278 * _MapKeyAttrToFlowPut --
1279 * Converts FLOW_KEY attribute to OvsFlowPut->key.
1280 *----------------------------------------------------------------------------
1283 _MapKeyAttrToFlowPut(PNL_ATTR
*keyAttrs
,
1284 PNL_ATTR
*tunnelAttrs
,
1285 OvsFlowKey
*destKey
)
1287 _MapTunAttrToFlowPut(keyAttrs
, tunnelAttrs
, destKey
);
1289 /* ===== L2 headers ===== */
1290 destKey
->l2
.inPort
= NlAttrGetU32(keyAttrs
[OVS_KEY_ATTR_IN_PORT
]);
1292 if (keyAttrs
[OVS_KEY_ATTR_ETHERNET
]) {
1293 const struct ovs_key_ethernet
*eth_key
;
1294 eth_key
= NlAttrGet(keyAttrs
[OVS_KEY_ATTR_ETHERNET
]);
1295 RtlCopyMemory(destKey
->l2
.dlSrc
, eth_key
->eth_src
, ETH_ADDR_LEN
);
1296 RtlCopyMemory(destKey
->l2
.dlDst
, eth_key
->eth_dst
, ETH_ADDR_LEN
);
1299 /* TODO: Ideally ETHERTYPE should not be optional.
1300 * But during vswitchd bootup we are seeing FLOW_ADD
1301 * requests with no ETHERTYPE attributes.
1302 * Need to verify this. */
1303 if (keyAttrs
[OVS_KEY_ATTR_ETHERTYPE
]) {
1304 destKey
->l2
.dlType
= (NlAttrGetU16(keyAttrs
1305 [OVS_KEY_ATTR_ETHERTYPE
]));
1308 if (keyAttrs
[OVS_KEY_ATTR_VLAN
]) {
1309 destKey
->l2
.vlanTci
= NlAttrGetU16(keyAttrs
[OVS_KEY_ATTR_VLAN
]);
1312 /* ==== L3 + L4. ==== */
1313 destKey
->l2
.keyLen
= OVS_WIN_TUNNEL_KEY_SIZE
+ OVS_L2_KEY_SIZE
1314 - destKey
->l2
.offset
;
1316 switch (ntohs(destKey
->l2
.dlType
)) {
1317 case ETH_TYPE_IPV4
: {
1319 if (keyAttrs
[OVS_KEY_ATTR_IPV4
]) {
1320 const struct ovs_key_ipv4
*ipv4Key
;
1322 ipv4Key
= NlAttrGet(keyAttrs
[OVS_KEY_ATTR_IPV4
]);
1323 IpKey
*ipv4FlowPutKey
= &(destKey
->ipKey
);
1324 ipv4FlowPutKey
->nwSrc
= ipv4Key
->ipv4_src
;
1325 ipv4FlowPutKey
->nwDst
= ipv4Key
->ipv4_dst
;
1326 ipv4FlowPutKey
->nwProto
= ipv4Key
->ipv4_proto
;
1327 ipv4FlowPutKey
->nwTos
= ipv4Key
->ipv4_tos
;
1328 ipv4FlowPutKey
->nwTtl
= ipv4Key
->ipv4_ttl
;
1329 ipv4FlowPutKey
->nwFrag
= ipv4Key
->ipv4_frag
;
1331 if (keyAttrs
[OVS_KEY_ATTR_TCP
]) {
1332 const struct ovs_key_tcp
*tcpKey
;
1333 tcpKey
= NlAttrGet(keyAttrs
[OVS_KEY_ATTR_TCP
]);
1334 ipv4FlowPutKey
->l4
.tpSrc
= tcpKey
->tcp_src
;
1335 ipv4FlowPutKey
->l4
.tpDst
= tcpKey
->tcp_dst
;
1338 if (keyAttrs
[OVS_KEY_ATTR_UDP
]) {
1339 const struct ovs_key_udp
*udpKey
;
1340 udpKey
= NlAttrGet(keyAttrs
[OVS_KEY_ATTR_UDP
]);
1341 ipv4FlowPutKey
->l4
.tpSrc
= udpKey
->udp_src
;
1342 ipv4FlowPutKey
->l4
.tpDst
= udpKey
->udp_dst
;
1345 if (keyAttrs
[OVS_KEY_ATTR_SCTP
]) {
1346 const struct ovs_key_sctp
*sctpKey
;
1347 sctpKey
= NlAttrGet(keyAttrs
[OVS_KEY_ATTR_SCTP
]);
1348 ipv4FlowPutKey
->l4
.tpSrc
= sctpKey
->sctp_src
;
1349 ipv4FlowPutKey
->l4
.tpDst
= sctpKey
->sctp_dst
;
1352 destKey
->l2
.keyLen
+= OVS_IP_KEY_SIZE
;
1356 case ETH_TYPE_IPV6
: {
1358 if (keyAttrs
[OVS_KEY_ATTR_IPV6
]) {
1359 const struct ovs_key_ipv6
*ipv6Key
;
1361 ipv6Key
= NlAttrGet(keyAttrs
[OVS_KEY_ATTR_IPV6
]);
1362 Ipv6Key
*ipv6FlowPutKey
= &(destKey
->ipv6Key
);
1364 RtlCopyMemory(&ipv6FlowPutKey
->ipv6Src
, ipv6Key
->ipv6_src
,
1365 sizeof ipv6Key
->ipv6_src
);
1366 RtlCopyMemory(&ipv6FlowPutKey
->ipv6Dst
, ipv6Key
->ipv6_dst
,
1367 sizeof ipv6Key
->ipv6_dst
);
1369 ipv6FlowPutKey
->ipv6Label
= ipv6Key
->ipv6_label
;
1370 ipv6FlowPutKey
->nwProto
= ipv6Key
->ipv6_proto
;
1371 ipv6FlowPutKey
->nwTos
= ipv6Key
->ipv6_tclass
;
1372 ipv6FlowPutKey
->nwTtl
= ipv6Key
->ipv6_hlimit
;
1373 ipv6FlowPutKey
->nwFrag
= ipv6Key
->ipv6_frag
;
1375 if (keyAttrs
[OVS_KEY_ATTR_TCP
]) {
1376 const struct ovs_key_tcp
*tcpKey
;
1377 tcpKey
= NlAttrGet(keyAttrs
[OVS_KEY_ATTR_TCP
]);
1378 ipv6FlowPutKey
->l4
.tpSrc
= tcpKey
->tcp_src
;
1379 ipv6FlowPutKey
->l4
.tpDst
= tcpKey
->tcp_dst
;
1382 if (keyAttrs
[OVS_KEY_ATTR_UDP
]) {
1383 const struct ovs_key_udp
*udpKey
;
1384 udpKey
= NlAttrGet(keyAttrs
[OVS_KEY_ATTR_UDP
]);
1385 ipv6FlowPutKey
->l4
.tpSrc
= udpKey
->udp_src
;
1386 ipv6FlowPutKey
->l4
.tpDst
= udpKey
->udp_dst
;
1389 if (keyAttrs
[OVS_KEY_ATTR_SCTP
]) {
1390 const struct ovs_key_sctp
*sctpKey
;
1391 sctpKey
= NlAttrGet(keyAttrs
[OVS_KEY_ATTR_SCTP
]);
1392 ipv6FlowPutKey
->l4
.tpSrc
= sctpKey
->sctp_src
;
1393 ipv6FlowPutKey
->l4
.tpDst
= sctpKey
->sctp_dst
;
1396 if (keyAttrs
[OVS_KEY_ATTR_ICMPV6
]) {
1397 const struct ovs_key_icmpv6
*icmpv6Key
;
1399 Icmp6Key
*icmp6FlowPutKey
= &(destKey
->icmp6Key
);
1401 icmpv6Key
= NlAttrGet(keyAttrs
[OVS_KEY_ATTR_ICMPV6
]);
1403 icmp6FlowPutKey
->l4
.tpSrc
= icmpv6Key
->icmpv6_type
;
1404 icmp6FlowPutKey
->l4
.tpDst
= icmpv6Key
->icmpv6_code
;
1406 if (keyAttrs
[OVS_KEY_ATTR_ND
]) {
1407 const struct ovs_key_nd
*ndKey
;
1409 ndKey
= NlAttrGet(keyAttrs
[OVS_KEY_ATTR_ND
]);
1410 RtlCopyMemory(&icmp6FlowPutKey
->ndTarget
,
1411 ndKey
->nd_target
, sizeof (icmp6FlowPutKey
->ndTarget
));
1412 RtlCopyMemory(icmp6FlowPutKey
->arpSha
,
1413 ndKey
->nd_sll
, ETH_ADDR_LEN
);
1414 RtlCopyMemory(icmp6FlowPutKey
->arpTha
,
1415 ndKey
->nd_tll
, ETH_ADDR_LEN
);
1418 destKey
->l2
.keyLen
+= OVS_ICMPV6_KEY_SIZE
;
1422 destKey
->l2
.keyLen
+= OVS_IPV6_KEY_SIZE
;
1425 ipv6FlowPutKey
->pad
= 0;
1430 case ETH_TYPE_RARP
: {
1432 if (keyAttrs
[OVS_KEY_ATTR_ARP
]) {
1433 ArpKey
*arpFlowPutKey
= &destKey
->arpKey
;
1434 const struct ovs_key_arp
*arpKey
;
1436 arpKey
= NlAttrGet(keyAttrs
[OVS_KEY_ATTR_ARP
]);
1438 arpFlowPutKey
->nwSrc
= arpKey
->arp_sip
;
1439 arpFlowPutKey
->nwDst
= arpKey
->arp_tip
;
1441 RtlCopyMemory(arpFlowPutKey
->arpSha
, arpKey
->arp_sha
, ETH_ADDR_LEN
);
1442 RtlCopyMemory(arpFlowPutKey
->arpTha
, arpKey
->arp_tha
, ETH_ADDR_LEN
);
1443 /* Kernel datapath assumes 'arpFlowPutKey->nwProto' to be in host
1445 arpFlowPutKey
->nwProto
= (UINT8
)ntohs((arpKey
->arp_op
));
1446 arpFlowPutKey
->pad
[0] = 0;
1447 arpFlowPutKey
->pad
[1] = 0;
1448 arpFlowPutKey
->pad
[2] = 0;
1449 destKey
->l2
.keyLen
+= OVS_ARP_KEY_SIZE
;
1457 *----------------------------------------------------------------------------
1458 * _MapTunAttrToFlowPut --
1459 * Converts FLOW_TUNNEL_KEY attribute to OvsFlowKey->tunKey.
1460 *----------------------------------------------------------------------------
1463 _MapTunAttrToFlowPut(PNL_ATTR
*keyAttrs
,
1465 OvsFlowKey
*destKey
)
1467 if (keyAttrs
[OVS_KEY_ATTR_TUNNEL
]) {
1469 if (tunAttrs
[OVS_TUNNEL_KEY_ATTR_ID
]) {
1470 destKey
->tunKey
.tunnelId
= NlAttrGetU64
1471 (tunAttrs
[OVS_TUNNEL_KEY_ATTR_ID
]);
1472 destKey
->tunKey
.flags
|= OVS_TNL_F_KEY
;
1475 if (tunAttrs
[OVS_TUNNEL_KEY_ATTR_IPV4_DST
]) {
1476 destKey
->tunKey
.dst
= NlAttrGetU32
1477 (tunAttrs
[OVS_TUNNEL_KEY_ATTR_IPV4_DST
]);
1480 if (tunAttrs
[OVS_TUNNEL_KEY_ATTR_IPV4_SRC
]) {
1481 destKey
->tunKey
.src
= NlAttrGetU32
1482 (tunAttrs
[OVS_TUNNEL_KEY_ATTR_IPV4_SRC
]);
1485 if (tunAttrs
[OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT
]) {
1486 destKey
->tunKey
.flags
|= OVS_TNL_F_DONT_FRAGMENT
;
1489 if (tunAttrs
[OVS_TUNNEL_KEY_ATTR_CSUM
]) {
1490 destKey
->tunKey
.flags
|= OVS_TNL_F_CSUM
;
1493 if (tunAttrs
[OVS_TUNNEL_KEY_ATTR_TOS
]) {
1494 destKey
->tunKey
.tos
= NlAttrGetU8
1495 (tunAttrs
[OVS_TUNNEL_KEY_ATTR_TOS
]);
1498 if (tunAttrs
[OVS_TUNNEL_KEY_ATTR_TTL
]) {
1499 destKey
->tunKey
.ttl
= NlAttrGetU8
1500 (tunAttrs
[OVS_TUNNEL_KEY_ATTR_TTL
]);
1503 destKey
->tunKey
.pad
= 0;
1504 destKey
->l2
.offset
= 0;
1506 destKey
->tunKey
.attr
[0] = 0;
1507 destKey
->tunKey
.attr
[1] = 0;
1508 destKey
->tunKey
.attr
[2] = 0;
1509 destKey
->l2
.offset
= sizeof destKey
->tunKey
;
1514 *----------------------------------------------------------------------------
1515 * OvsDeleteFlowTable --
1517 * NDIS_STATUS_SUCCESS always.
1518 *----------------------------------------------------------------------------
1521 OvsDeleteFlowTable(OVS_DATAPATH
*datapath
)
1523 if (datapath
== NULL
|| datapath
->flowTable
== NULL
) {
1524 return NDIS_STATUS_SUCCESS
;
1527 DeleteAllFlows(datapath
);
1528 OvsFreeMemoryWithTag(datapath
->flowTable
, OVS_FLOW_POOL_TAG
);
1529 datapath
->flowTable
= NULL
;
1531 if (datapath
->lock
== NULL
) {
1532 return NDIS_STATUS_SUCCESS
;
1535 NdisFreeRWLock(datapath
->lock
);
1537 return NDIS_STATUS_SUCCESS
;
1541 *----------------------------------------------------------------------------
1542 * OvsAllocateFlowTable --
1544 * NDIS_STATUS_SUCCESS on success.
1545 * NDIS_STATUS_RESOURCES if memory couldn't be allocated
1546 *----------------------------------------------------------------------------
1549 OvsAllocateFlowTable(OVS_DATAPATH
*datapath
,
1550 POVS_SWITCH_CONTEXT switchContext
)
1555 datapath
->flowTable
= OvsAllocateMemoryWithTag(
1556 OVS_FLOW_TABLE_SIZE
* sizeof(LIST_ENTRY
), OVS_FLOW_POOL_TAG
);
1557 if (!datapath
->flowTable
) {
1558 return NDIS_STATUS_RESOURCES
;
1560 for (i
= 0; i
< OVS_FLOW_TABLE_SIZE
; i
++) {
1561 bucket
= &(datapath
->flowTable
[i
]);
1562 InitializeListHead(bucket
);
1564 datapath
->lock
= NdisAllocateRWLock(switchContext
->NdisFilterHandle
);
1566 if (!datapath
->lock
) {
1567 return NDIS_STATUS_RESOURCES
;
1570 return NDIS_STATUS_SUCCESS
;
1575 *----------------------------------------------------------------------------
1576 * GetStartAddrNBL --
1577 * Get the virtual address of the frame.
1580 * Virtual address of the frame.
1581 *----------------------------------------------------------------------------
1583 static __inline VOID
*
1584 GetStartAddrNBL(const NET_BUFFER_LIST
*_pNB
)
1592 // Ethernet Header is a guaranteed safe access.
1593 curMdl
= (NET_BUFFER_LIST_FIRST_NB(_pNB
))->CurrentMdl
;
1594 curBuffer
= MmGetSystemAddressForMdlSafe(curMdl
, LowPagePriority
);
1599 curHeader
= (PEthHdr
)
1600 (curBuffer
+ (NET_BUFFER_LIST_FIRST_NB(_pNB
))->CurrentMdlOffset
);
1602 return (VOID
*) curHeader
;
1606 OvsFlowUsed(OvsFlow
*flow
,
1607 const NET_BUFFER_LIST
*packet
,
1608 const POVS_PACKET_HDR_INFO layers
)
1610 LARGE_INTEGER tickCount
;
1612 KeQueryTickCount(&tickCount
);
1613 flow
->used
= tickCount
.QuadPart
* ovsTimeIncrementPerTick
;
1614 flow
->packetCount
++;
1615 flow
->byteCount
+= OvsPacketLenNBL(packet
);
1616 flow
->tcpFlags
|= OvsGetTcpFlags(packet
, &flow
->key
, layers
);
1621 DeleteAllFlows(OVS_DATAPATH
*datapath
)
1626 for (i
= 0; i
< OVS_FLOW_TABLE_SIZE
; i
++) {
1628 bucket
= &(datapath
->flowTable
[i
]);
1629 while (!IsListEmpty(bucket
)) {
1631 next
= bucket
->Flink
;
1632 flow
= CONTAINING_RECORD(next
, OvsFlow
, ListEntry
);
1633 RemoveFlow(datapath
, &flow
);
1639 *----------------------------------------------------------------------------
1640 * Initializes 'flow' members from 'packet', 'skb_priority', 'tun_id', and
1643 * Initializes 'packet' header pointers as follows:
1645 * - packet->l2 to the start of the Ethernet header.
1647 * - packet->l3 to just past the Ethernet header, or just past the
1648 * vlan_header if one is present, to the first byte of the payload of the
1651 * - packet->l4 to just past the IPv4 header, if one is present and has a
1652 * correct length, and otherwise NULL.
1654 * - packet->l7 to just past the TCP or UDP or ICMP header, if one is
1655 * present and has a correct length, and otherwise NULL.
1657 * Returns NDIS_STATUS_SUCCESS normally. Fails only if packet data cannot be accessed
1658 * (e.g. if Pkt_CopyBytesOut() returns an error).
1659 *----------------------------------------------------------------------------
1662 OvsExtractFlow(const NET_BUFFER_LIST
*packet
,
1665 POVS_PACKET_HDR_INFO layers
,
1666 OvsIPv4TunnelKey
*tunKey
)
1668 struct Eth_Header
*eth
;
1675 ASSERT(tunKey
->dst
!= 0);
1676 RtlMoveMemory(&flow
->tunKey
, tunKey
, sizeof flow
->tunKey
);
1677 flow
->l2
.offset
= 0;
1679 flow
->tunKey
.dst
= 0;
1680 flow
->l2
.offset
= OVS_WIN_TUNNEL_KEY_SIZE
;
1683 flow
->l2
.inPort
= inPort
;
1685 if ( OvsPacketLenNBL(packet
) < ETH_HEADER_LEN_DIX
) {
1686 flow
->l2
.keyLen
= OVS_WIN_TUNNEL_KEY_SIZE
+ 8 - flow
->l2
.offset
;
1687 return NDIS_STATUS_SUCCESS
;
1691 eth
= (Eth_Header
*)GetStartAddrNBL((NET_BUFFER_LIST
*)packet
);
1692 memcpy(flow
->l2
.dlSrc
, eth
->src
, ETH_ADDR_LENGTH
);
1693 memcpy(flow
->l2
.dlDst
, eth
->dst
, ETH_ADDR_LENGTH
);
1698 vlanTagValue
= NET_BUFFER_LIST_INFO(packet
, Ieee8021QNetBufferListInfo
);
1700 PNDIS_NET_BUFFER_LIST_8021Q_INFO vlanTag
=
1701 (PNDIS_NET_BUFFER_LIST_8021Q_INFO
)(PVOID
*)&vlanTagValue
;
1702 flow
->l2
.vlanTci
= htons(vlanTag
->TagHeader
.VlanId
| OVSWIN_VLAN_CFI
|
1703 (vlanTag
->TagHeader
.UserPriority
<< 13));
1705 if (eth
->dix
.typeNBO
== ETH_TYPE_802_1PQ_NBO
) {
1706 Eth_802_1pq_Tag
*tag
= (Eth_802_1pq_Tag
*)ð
->dix
.typeNBO
;
1707 flow
->l2
.vlanTci
= ((UINT16
)tag
->priority
<< 13) |
1709 ((UINT16
)tag
->vidHi
<< 8) | tag
->vidLo
;
1710 offset
= sizeof (Eth_802_1pq_Tag
);
1712 flow
->l2
.vlanTci
= 0;
1716 * Please note after this point, src mac and dst mac should
1717 * not be accessed through eth
1719 eth
= (Eth_Header
*)((UINT8
*)eth
+ offset
);
1725 * XXX assume that at least the first
1726 * 12 bytes of received packets are mapped. This code has the stronger
1727 * assumption that at least the first 22 bytes of 'packet' is mapped (if my
1728 * arithmetic is right).
1730 if (ETH_TYPENOT8023(eth
->dix
.typeNBO
)) {
1731 flow
->l2
.dlType
= eth
->dix
.typeNBO
;
1732 layers
->l3Offset
= ETH_HEADER_LEN_DIX
+ offset
;
1733 } else if (OvsPacketLenNBL(packet
) >= ETH_HEADER_LEN_802_3
&&
1734 eth
->e802_3
.llc
.dsap
== 0xaa &&
1735 eth
->e802_3
.llc
.ssap
== 0xaa &&
1736 eth
->e802_3
.llc
.control
== ETH_LLC_CONTROL_UFRAME
&&
1737 eth
->e802_3
.snap
.snapOrg
[0] == 0x00 &&
1738 eth
->e802_3
.snap
.snapOrg
[1] == 0x00 &&
1739 eth
->e802_3
.snap
.snapOrg
[2] == 0x00) {
1740 flow
->l2
.dlType
= eth
->e802_3
.snap
.snapType
.typeNBO
;
1741 layers
->l3Offset
= ETH_HEADER_LEN_802_3
+ offset
;
1743 flow
->l2
.dlType
= htons(OVSWIN_DL_TYPE_NONE
);
1744 layers
->l3Offset
= ETH_HEADER_LEN_DIX
+ offset
;
1747 flow
->l2
.keyLen
= OVS_WIN_TUNNEL_KEY_SIZE
+ OVS_L2_KEY_SIZE
- flow
->l2
.offset
;
1748 /* Network layer. */
1749 if (flow
->l2
.dlType
== htons(ETH_TYPE_IPV4
)) {
1750 struct IPHdr ip_storage
;
1751 const struct IPHdr
*nh
;
1752 IpKey
*ipKey
= &flow
->ipKey
;
1754 flow
->l2
.keyLen
+= OVS_IP_KEY_SIZE
;
1756 nh
= OvsGetIp(packet
, layers
->l3Offset
, &ip_storage
);
1758 layers
->l4Offset
= layers
->l3Offset
+ nh
->ihl
* 4;
1760 ipKey
->nwSrc
= nh
->saddr
;
1761 ipKey
->nwDst
= nh
->daddr
;
1762 ipKey
->nwProto
= nh
->protocol
;
1764 ipKey
->nwTos
= nh
->tos
;
1765 if (nh
->frag_off
& htons(IP_MF
| IP_OFFSET
)) {
1766 ipKey
->nwFrag
= OVSWIN_NW_FRAG_ANY
;
1767 if (nh
->frag_off
& htons(IP_OFFSET
)) {
1768 ipKey
->nwFrag
|= OVSWIN_NW_FRAG_LATER
;
1774 ipKey
->nwTtl
= nh
->ttl
;
1775 ipKey
->l4
.tpSrc
= 0;
1776 ipKey
->l4
.tpDst
= 0;
1778 if (!(nh
->frag_off
& htons(IP_OFFSET
))) {
1779 if (ipKey
->nwProto
== SOCKET_IPPROTO_TCP
) {
1780 OvsParseTcp(packet
, &ipKey
->l4
, layers
);
1781 } else if (ipKey
->nwProto
== SOCKET_IPPROTO_UDP
) {
1782 OvsParseUdp(packet
, &ipKey
->l4
, layers
);
1783 } else if (ipKey
->nwProto
== SOCKET_IPPROTO_ICMP
) {
1784 ICMPHdr icmpStorage
;
1785 const ICMPHdr
*icmp
;
1787 icmp
= OvsGetIcmp(packet
, layers
->l4Offset
, &icmpStorage
);
1789 ipKey
->l4
.tpSrc
= htons(icmp
->type
);
1790 ipKey
->l4
.tpDst
= htons(icmp
->code
);
1791 layers
->l7Offset
= layers
->l4Offset
+ sizeof *icmp
;
1796 ((UINT64
*)ipKey
)[0] = 0;
1797 ((UINT64
*)ipKey
)[1] = 0;
1799 } else if (flow
->l2
.dlType
== htons(ETH_TYPE_IPV6
)) {
1801 flow
->l2
.keyLen
+= OVS_IPV6_KEY_SIZE
;
1802 status
= OvsParseIPv6(packet
, flow
, layers
);
1803 if (status
!= NDIS_STATUS_SUCCESS
) {
1804 memset(&flow
->ipv6Key
, 0, sizeof (Ipv6Key
));
1808 flow
->ipv6Key
.l4
.tpSrc
= 0;
1809 flow
->ipv6Key
.l4
.tpDst
= 0;
1810 flow
->ipv6Key
.pad
= 0;
1812 if (flow
->ipv6Key
.nwProto
== SOCKET_IPPROTO_TCP
) {
1813 OvsParseTcp(packet
, &(flow
->ipv6Key
.l4
), layers
);
1814 } else if (flow
->ipv6Key
.nwProto
== SOCKET_IPPROTO_UDP
) {
1815 OvsParseUdp(packet
, &(flow
->ipv6Key
.l4
), layers
);
1816 } else if (flow
->ipv6Key
.nwProto
== SOCKET_IPPROTO_ICMPV6
) {
1817 OvsParseIcmpV6(packet
, flow
, layers
);
1818 flow
->l2
.keyLen
+= (OVS_ICMPV6_KEY_SIZE
- OVS_IPV6_KEY_SIZE
);
1820 } else if (flow
->l2
.dlType
== htons(ETH_TYPE_ARP
)) {
1821 EtherArp arpStorage
;
1822 const EtherArp
*arp
;
1823 ArpKey
*arpKey
= &flow
->arpKey
;
1824 ((UINT64
*)arpKey
)[0] = 0;
1825 ((UINT64
*)arpKey
)[1] = 0;
1826 ((UINT64
*)arpKey
)[2] = 0;
1827 flow
->l2
.keyLen
+= OVS_ARP_KEY_SIZE
;
1828 arp
= OvsGetArp(packet
, layers
->l3Offset
, &arpStorage
);
1829 if (arp
&& arp
->ea_hdr
.ar_hrd
== htons(1) &&
1830 arp
->ea_hdr
.ar_pro
== htons(ETH_TYPE_IPV4
) &&
1831 arp
->ea_hdr
.ar_hln
== ETH_ADDR_LENGTH
&&
1832 arp
->ea_hdr
.ar_pln
== 4) {
1833 /* We only match on the lower 8 bits of the opcode. */
1834 if (ntohs(arp
->ea_hdr
.ar_op
) <= 0xff) {
1835 arpKey
->nwProto
= (UINT8
)ntohs(arp
->ea_hdr
.ar_op
);
1837 if (arpKey
->nwProto
== ARPOP_REQUEST
1838 || arpKey
->nwProto
== ARPOP_REPLY
) {
1839 memcpy(&arpKey
->nwSrc
, arp
->arp_spa
, 4);
1840 memcpy(&arpKey
->nwDst
, arp
->arp_tpa
, 4);
1841 memcpy(arpKey
->arpSha
, arp
->arp_sha
, ETH_ADDR_LENGTH
);
1842 memcpy(arpKey
->arpTha
, arp
->arp_tha
, ETH_ADDR_LENGTH
);
1847 return NDIS_STATUS_SUCCESS
;
1851 FlowEqual(UINT64
*src
, UINT64
*dst
, UINT32 size
)
1854 ASSERT((size
& 0x7) == 0);
1855 ASSERT(((UINT64
)src
& 0x7) == 0);
1856 ASSERT(((UINT64
)dst
& 0x7) == 0);
1857 for (i
= 0; i
< (size
>> 3); i
++) {
1858 if (src
[i
] != dst
[i
]) {
1867 * ----------------------------------------------------------------------------
1869 * Add a flow to flow table.
1872 * NDIS_STATUS_SUCCESS if no same flow in the flow table.
1873 * ----------------------------------------------------------------------------
1876 AddFlow(OVS_DATAPATH
*datapath
, OvsFlow
*flow
)
1880 if (OvsLookupFlow(datapath
, &flow
->key
, &flow
->hash
, TRUE
) != NULL
) {
1881 return STATUS_INVALID_HANDLE
;
1884 head
= &(datapath
->flowTable
[HASH_BUCKET(flow
->hash
)]);
1886 * We need fence here to make sure flow's nextPtr is updated before
1887 * head->nextPtr is updated.
1891 //KeAcquireSpinLock(&FilterDeviceExtension->NblQueueLock, &oldIrql);
1892 InsertTailList(head
, &flow
->ListEntry
);
1893 //KeReleaseSpinLock(&FilterDeviceExtension->NblQueueLock, oldIrql);
1897 return STATUS_SUCCESS
;
1901 /* ----------------------------------------------------------------------------
1903 * Remove a flow from flow table, and added to wait list
1904 * ----------------------------------------------------------------------------
1907 RemoveFlow(OVS_DATAPATH
*datapath
,
1913 ASSERT(datapath
->nFlows
);
1915 // Remove the flow from queue
1916 RemoveEntryList(&f
->ListEntry
);
1922 * ----------------------------------------------------------------------------
1925 * Find flow from flow table based on flow key.
1926 * Caller should either hold portset handle or should
1927 * have a flowRef in datapath or Acquired datapath.
1930 * Flow pointer if lookup successful.
1931 * NULL if not exists.
1932 * ----------------------------------------------------------------------------
1935 OvsLookupFlow(OVS_DATAPATH
*datapath
,
1936 const OvsFlowKey
*key
,
1940 PLIST_ENTRY link
, head
;
1941 UINT16 offset
= key
->l2
.offset
;
1942 UINT16 size
= key
->l2
.keyLen
;
1945 ASSERT(key
->tunKey
.dst
|| offset
== sizeof (OvsIPv4TunnelKey
));
1946 ASSERT(!key
->tunKey
.dst
|| offset
== 0);
1948 start
= (UINT8
*)key
+ offset
;
1951 *hash
= OvsJhashBytes(start
, size
, 0);
1954 head
= &datapath
->flowTable
[HASH_BUCKET(*hash
)];
1956 while (link
!= head
) {
1957 OvsFlow
*flow
= CONTAINING_RECORD(link
, OvsFlow
, ListEntry
);
1959 if (flow
->hash
== *hash
&&
1960 flow
->key
.l2
.val
== key
->l2
.val
&&
1961 FlowEqual((UINT64
*)((uint8
*)&flow
->key
+ offset
),
1962 (UINT64
*)start
, size
)) {
1972 * ----------------------------------------------------------------------------
1974 * Calculate the hash for the given flow key.
1975 * ----------------------------------------------------------------------------
1978 OvsHashFlow(const OvsFlowKey
*key
)
1980 UINT16 offset
= key
->l2
.offset
;
1981 UINT16 size
= key
->l2
.keyLen
;
1984 ASSERT(key
->tunKey
.dst
|| offset
== sizeof (OvsIPv4TunnelKey
));
1985 ASSERT(!key
->tunKey
.dst
|| offset
== 0);
1986 start
= (UINT8
*)key
+ offset
;
1987 return OvsJhashBytes(start
, size
, 0);
1992 * ----------------------------------------------------------------------------
1994 * Free a flow and its actions.
1995 * ----------------------------------------------------------------------------
1998 FreeFlow(OvsFlow
*flow
)
2001 OvsFreeMemoryWithTag(flow
, OVS_FLOW_POOL_TAG
);
2005 OvsDoDumpFlows(OvsFlowDumpInput
*dumpInput
,
2006 OvsFlowDumpOutput
*dumpOutput
,
2010 OVS_DATAPATH
*datapath
= NULL
;
2012 PLIST_ENTRY node
, head
;
2014 UINT32 rowIndex
, columnIndex
;
2015 LOCK_STATE_EX dpLockState
;
2016 NTSTATUS status
= STATUS_SUCCESS
;
2017 BOOLEAN findNextNonEmpty
= FALSE
;
2019 dpNo
= dumpInput
->dpNo
;
2020 if (gOvsSwitchContext
->dpNo
!= dpNo
) {
2021 status
= STATUS_INVALID_PARAMETER
;
2025 rowIndex
= dumpInput
->position
[0];
2026 if (rowIndex
>= OVS_FLOW_TABLE_SIZE
) {
2028 *replyLen
= sizeof(*dumpOutput
);
2032 columnIndex
= dumpInput
->position
[1];
2034 datapath
= &gOvsSwitchContext
->datapath
;
2036 OvsAcquireDatapathRead(datapath
, &dpLockState
, FALSE
);
2038 head
= &datapath
->flowTable
[rowIndex
];
2041 while (column
< columnIndex
) {
2050 findNextNonEmpty
= TRUE
;
2054 if (findNextNonEmpty
) {
2055 while (head
== node
) {
2056 if (++rowIndex
>= OVS_FLOW_TABLE_SIZE
) {
2060 head
= &datapath
->flowTable
[rowIndex
];
2065 ASSERT(node
!= head
);
2066 ASSERT(rowIndex
< OVS_FLOW_TABLE_SIZE
);
2068 flow
= CONTAINING_RECORD(node
, OvsFlow
, ListEntry
);
2069 status
= ReportFlowInfo(flow
, dumpInput
->getFlags
, &dumpOutput
->flow
);
2071 if (status
== STATUS_BUFFER_TOO_SMALL
) {
2072 dumpOutput
->n
= sizeof(OvsFlowDumpOutput
) + flow
->actionsLen
;
2073 *replyLen
= sizeof(*dumpOutput
);
2075 dumpOutput
->n
= 1; //one flow reported.
2076 *replyLen
= sizeof(*dumpOutput
) + dumpOutput
->flow
.actionsLen
;
2079 dumpOutput
->position
[0] = rowIndex
;
2080 dumpOutput
->position
[1] = ++columnIndex
;
2083 OvsReleaseDatapath(datapath
, &dpLockState
);
2090 ReportFlowInfo(OvsFlow
*flow
,
2094 NTSTATUS status
= STATUS_SUCCESS
;
2096 if (getFlags
& FLOW_GET_KEY
) {
2097 // always copy the tunnel key part
2098 RtlCopyMemory(&info
->key
, &flow
->key
,
2099 flow
->key
.l2
.keyLen
+ flow
->key
.l2
.offset
);
2102 if (getFlags
& FLOW_GET_STATS
) {
2103 OvsFlowStats
*stats
= &info
->stats
;
2104 stats
->packetCount
= flow
->packetCount
;
2105 stats
->byteCount
= flow
->byteCount
;
2106 stats
->used
= (UINT32
)flow
->used
;
2107 stats
->tcpFlags
= flow
->tcpFlags
;
2110 if (getFlags
& FLOW_GET_ACTIONS
) {
2111 if (flow
->actionsLen
== 0) {
2112 info
->actionsLen
= 0;
2114 info
->actions
= flow
->actions
;
2115 info
->actionsLen
= flow
->actionsLen
;
2123 OvsPutFlowIoctl(PVOID inputBuffer
,
2125 struct OvsFlowStats
*stats
)
2127 NTSTATUS status
= STATUS_SUCCESS
;
2128 OVS_DATAPATH
*datapath
= NULL
;
2132 LOCK_STATE_EX dpLockState
;
2134 if ((inputLength
< sizeof(OvsFlowPut
)) || (inputBuffer
== NULL
)) {
2135 return STATUS_INFO_LENGTH_MISMATCH
;
2138 put
= (OvsFlowPut
*)inputBuffer
;
2139 if (put
->actionsLen
> 0) {
2140 actionsLen
= put
->actionsLen
;
2146 if (gOvsSwitchContext
->dpNo
!= dpNo
) {
2147 status
= STATUS_INVALID_PARAMETER
;
2151 datapath
= &gOvsSwitchContext
->datapath
;
2153 OvsAcquireDatapathWrite(datapath
, &dpLockState
, FALSE
);
2154 status
= HandleFlowPut(put
, datapath
, stats
);
2155 OvsReleaseDatapath(datapath
, &dpLockState
);
2162 /* Handles flow add, modify as well as delete */
2164 HandleFlowPut(OvsFlowPut
*put
,
2165 OVS_DATAPATH
*datapath
,
2166 struct OvsFlowStats
*stats
)
2168 BOOLEAN mayCreate
, mayModify
, mayDelete
;
2169 OvsFlow
*KernelFlow
;
2171 NTSTATUS status
= STATUS_SUCCESS
;
2173 mayCreate
= (put
->flags
& OVSWIN_FLOW_PUT_CREATE
) != 0;
2174 mayModify
= (put
->flags
& OVSWIN_FLOW_PUT_MODIFY
) != 0;
2175 mayDelete
= (put
->flags
& OVSWIN_FLOW_PUT_DELETE
) != 0;
2177 if ((mayCreate
|| mayModify
) == mayDelete
) {
2178 return STATUS_INVALID_PARAMETER
;
2181 KernelFlow
= OvsLookupFlow(datapath
, &put
->key
, &hash
, FALSE
);
2184 return STATUS_INVALID_PARAMETER
;
2187 status
= OvsPrepareFlow(&KernelFlow
, put
, hash
);
2188 if (status
!= STATUS_SUCCESS
) {
2189 return STATUS_UNSUCCESSFUL
;
2192 status
= AddFlow(datapath
, KernelFlow
);
2193 if (status
!= STATUS_SUCCESS
) {
2194 FreeFlow(KernelFlow
);
2195 return STATUS_UNSUCCESSFUL
;
2198 /* Validate the flow addition */
2201 OvsFlow
*flow
= OvsLookupFlow(datapath
, &put
->key
, &newHash
,
2204 ASSERT(newHash
== hash
);
2205 if (!flow
|| newHash
!= hash
) {
2206 return STATUS_UNSUCCESSFUL
;
2210 stats
->packetCount
= KernelFlow
->packetCount
;
2211 stats
->byteCount
= KernelFlow
->byteCount
;
2212 stats
->tcpFlags
= KernelFlow
->tcpFlags
;
2213 stats
->used
= (UINT32
)KernelFlow
->used
;
2217 status
= OvsPrepareFlow(&newFlow
, put
, hash
);
2218 if (status
!= STATUS_SUCCESS
) {
2219 return STATUS_UNSUCCESSFUL
;
2222 KernelFlow
= OvsLookupFlow(datapath
, &put
->key
, &hash
, TRUE
);
2224 if ((put
->flags
& OVSWIN_FLOW_PUT_CLEAR
) == 0) {
2225 newFlow
->packetCount
= KernelFlow
->packetCount
;
2226 newFlow
->byteCount
= KernelFlow
->byteCount
;
2227 newFlow
->tcpFlags
= KernelFlow
->tcpFlags
;
2229 RemoveFlow(datapath
, &KernelFlow
);
2231 if ((put
->flags
& OVSWIN_FLOW_PUT_CLEAR
) == 0) {
2232 newFlow
->packetCount
= stats
->packetCount
;
2233 newFlow
->byteCount
= stats
->byteCount
;
2234 newFlow
->tcpFlags
= stats
->tcpFlags
;
2237 status
= AddFlow(datapath
, newFlow
);
2238 ASSERT(status
== STATUS_SUCCESS
);
2240 /* Validate the flow addition */
2243 OvsFlow
*testflow
= OvsLookupFlow(datapath
, &put
->key
,
2246 ASSERT(newHash
== hash
);
2247 if (!testflow
|| newHash
!= hash
) {
2249 return STATUS_UNSUCCESSFUL
;
2255 RemoveFlow(datapath
, &KernelFlow
);
2258 /* Return success if an identical flow already exists. */
2259 /* XXX: should we return EEXIST in a netlink error? */
2260 return STATUS_SUCCESS
;
2264 return STATUS_SUCCESS
;
2268 OvsPrepareFlow(OvsFlow
**flow
,
2269 const OvsFlowPut
*put
,
2272 OvsFlow
*localFlow
= *flow
;
2273 NTSTATUS status
= STATUS_SUCCESS
;
2277 OvsAllocateMemoryWithTag(sizeof(OvsFlow
) + put
->actionsLen
,
2279 if (localFlow
== NULL
) {
2280 status
= STATUS_NO_MEMORY
;
2284 localFlow
->key
= put
->key
;
2285 localFlow
->actionsLen
= put
->actionsLen
;
2286 if (put
->actionsLen
) {
2287 NdisMoveMemory((PUCHAR
)localFlow
->actions
, put
->actions
,
2290 localFlow
->userActionsLen
= 0; // 0 indicate no conversion is made
2291 localFlow
->used
= 0;
2292 localFlow
->packetCount
= 0;
2293 localFlow
->byteCount
= 0;
2294 localFlow
->tcpFlags
= 0;
2295 localFlow
->hash
= hash
;
2302 OvsGetFlowIoctl(PVOID inputBuffer
,
2305 NTSTATUS status
= STATUS_SUCCESS
;
2306 OVS_DATAPATH
*datapath
= NULL
;
2308 UINT32 getFlags
, getActionsLen
;
2309 OvsFlowGetInput
*getInput
;
2310 OvsFlowGetOutput
*getOutput
;
2313 LOCK_STATE_EX dpLockState
;
2315 getInput
= (OvsFlowGetInput
*) inputBuffer
;
2316 getFlags
= getInput
->getFlags
;
2317 getActionsLen
= getInput
->actionsLen
;
2319 if (outputBuffer
== NULL
) {
2320 return STATUS_INFO_LENGTH_MISMATCH
;
2323 dpNo
= getInput
->dpNo
;
2324 if (gOvsSwitchContext
->dpNo
!= dpNo
) {
2325 status
= STATUS_INVALID_PARAMETER
;
2329 datapath
= &gOvsSwitchContext
->datapath
;
2331 OvsAcquireDatapathRead(datapath
, &dpLockState
, FALSE
);
2332 flow
= OvsLookupFlow(datapath
, &getInput
->key
, &hash
, FALSE
);
2334 status
= STATUS_INVALID_PARAMETER
;
2338 getOutput
= (OvsFlowGetOutput
*)outputBuffer
;
2339 ReportFlowInfo(flow
, getFlags
, &getOutput
->info
);
2342 OvsReleaseDatapath(datapath
, &dpLockState
);
2348 OvsFlushFlowIoctl(UINT32 dpNo
)
2350 NTSTATUS status
= STATUS_SUCCESS
;
2351 OVS_DATAPATH
*datapath
= NULL
;
2352 LOCK_STATE_EX dpLockState
;
2354 if (gOvsSwitchContext
->dpNo
!= dpNo
) {
2355 status
= STATUS_INVALID_PARAMETER
;
2359 datapath
= &gOvsSwitchContext
->datapath
;
2361 OvsAcquireDatapathWrite(datapath
, &dpLockState
, FALSE
);
2362 DeleteAllFlows(datapath
);
2363 OvsReleaseDatapath(datapath
, &dpLockState
);
2370 OvsFlowKeyAttrSize(void)
2372 return NlAttrTotalSize(4) /* OVS_KEY_ATTR_PRIORITY */
2373 + NlAttrTotalSize(0) /* OVS_KEY_ATTR_TUNNEL */
2374 + OvsTunKeyAttrSize()
2375 + NlAttrTotalSize(4) /* OVS_KEY_ATTR_IN_PORT */
2376 + NlAttrTotalSize(4) /* OVS_KEY_ATTR_SKB_MARK */
2377 + NlAttrTotalSize(4) /* OVS_KEY_ATTR_DP_HASH */
2378 + NlAttrTotalSize(4) /* OVS_KEY_ATTR_RECIRC_ID */
2379 + NlAttrTotalSize(12) /* OVS_KEY_ATTR_ETHERNET */
2380 + NlAttrTotalSize(2) /* OVS_KEY_ATTR_ETHERTYPE */
2381 + NlAttrTotalSize(4) /* OVS_KEY_ATTR_VLAN */
2382 + NlAttrTotalSize(0) /* OVS_KEY_ATTR_ENCAP */
2383 + NlAttrTotalSize(2) /* OVS_KEY_ATTR_ETHERTYPE */
2384 + NlAttrTotalSize(40) /* OVS_KEY_ATTR_IPV6 */
2385 + NlAttrTotalSize(2) /* OVS_KEY_ATTR_ICMPV6 */
2386 + NlAttrTotalSize(28); /* OVS_KEY_ATTR_ND */
2390 OvsTunKeyAttrSize(void)
2392 /* Whenever adding new OVS_TUNNEL_KEY_ FIELDS, we should consider
2393 * updating this function.
2395 return NlAttrTotalSize(8) /* OVS_TUNNEL_KEY_ATTR_ID */
2396 + NlAttrTotalSize(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_SRC */
2397 + NlAttrTotalSize(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_DST */
2398 + NlAttrTotalSize(1) /* OVS_TUNNEL_KEY_ATTR_TOS */
2399 + NlAttrTotalSize(1) /* OVS_TUNNEL_KEY_ATTR_TTL */
2400 + NlAttrTotalSize(0) /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */
2401 + NlAttrTotalSize(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */
2402 + NlAttrTotalSize(0) /* OVS_TUNNEL_KEY_ATTR_OAM */
2403 + NlAttrTotalSize(256) /* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS */
2404 + NlAttrTotalSize(2) /* OVS_TUNNEL_KEY_ATTR_TP_SRC */
2405 + NlAttrTotalSize(2); /* OVS_TUNNEL_KEY_ATTR_TP_DST */
2408 #pragma warning( pop )