]>
git.proxmox.com Git - mirror_ovs.git/blob - lib/flow.c
2 * Copyright (c) 2008, 2009, 2010 Nicira Networks.
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.
17 #include <sys/types.h>
20 #include <netinet/in.h>
24 #include "dynamic-string.h"
27 #include "openflow/openflow.h"
28 #include "openvswitch/datapath-protocol.h"
30 #include "unaligned.h"
34 VLOG_DEFINE_THIS_MODULE(flow
)
36 static struct arp_eth_header
*
37 pull_arp(struct ofpbuf
*packet
)
39 return ofpbuf_try_pull(packet
, ARP_ETH_HEADER_LEN
);
42 static struct ip_header
*
43 pull_ip(struct ofpbuf
*packet
)
45 if (packet
->size
>= IP_HEADER_LEN
) {
46 struct ip_header
*ip
= packet
->data
;
47 int ip_len
= IP_IHL(ip
->ip_ihl_ver
) * 4;
48 if (ip_len
>= IP_HEADER_LEN
&& packet
->size
>= ip_len
) {
49 return ofpbuf_pull(packet
, ip_len
);
55 static struct tcp_header
*
56 pull_tcp(struct ofpbuf
*packet
)
58 if (packet
->size
>= TCP_HEADER_LEN
) {
59 struct tcp_header
*tcp
= packet
->data
;
60 int tcp_len
= TCP_OFFSET(tcp
->tcp_ctl
) * 4;
61 if (tcp_len
>= TCP_HEADER_LEN
&& packet
->size
>= tcp_len
) {
62 return ofpbuf_pull(packet
, tcp_len
);
68 static struct udp_header
*
69 pull_udp(struct ofpbuf
*packet
)
71 return ofpbuf_try_pull(packet
, UDP_HEADER_LEN
);
74 static struct icmp_header
*
75 pull_icmp(struct ofpbuf
*packet
)
77 return ofpbuf_try_pull(packet
, ICMP_HEADER_LEN
);
81 parse_vlan(struct ofpbuf
*b
, flow_t
*flow
)
84 uint16_t eth_type
; /* ETH_TYPE_VLAN */
88 if (b
->size
>= sizeof(struct qtag_prefix
) + sizeof(uint16_t)) {
89 struct qtag_prefix
*qp
= ofpbuf_pull(b
, sizeof *qp
);
90 flow
->dl_vlan
= qp
->tci
& htons(VLAN_VID_MASK
);
91 flow
->dl_vlan_pcp
= (ntohs(qp
->tci
) & VLAN_PCP_MASK
) >> VLAN_PCP_SHIFT
;
96 parse_ethertype(struct ofpbuf
*b
)
98 struct llc_snap_header
*llc
;
101 proto
= *(uint16_t *) ofpbuf_pull(b
, sizeof proto
);
102 if (ntohs(proto
) >= ODP_DL_TYPE_ETH2_CUTOFF
) {
106 if (b
->size
< sizeof *llc
) {
107 return htons(ODP_DL_TYPE_NOT_ETH_TYPE
);
111 if (llc
->llc
.llc_dsap
!= LLC_DSAP_SNAP
112 || llc
->llc
.llc_ssap
!= LLC_SSAP_SNAP
113 || llc
->llc
.llc_cntl
!= LLC_CNTL_SNAP
114 || memcmp(llc
->snap
.snap_org
, SNAP_ORG_ETHERNET
,
115 sizeof llc
->snap
.snap_org
)) {
116 return htons(ODP_DL_TYPE_NOT_ETH_TYPE
);
119 ofpbuf_pull(b
, sizeof *llc
);
120 return llc
->snap
.snap_type
;
123 /* 'tun_id' is in network byte order, while 'in_port' is in host byte order.
124 * These byte orders are the same as they are in struct odp_flow_key.
126 * Initializes packet header pointers as follows:
128 * - packet->l2 to the start of the Ethernet header.
130 * - packet->l3 to just past the Ethernet header, or just past the
131 * vlan_header if one is present, to the first byte of the payload of the
134 * - packet->l4 to just past the IPv4 header, if one is present and has a
135 * correct length, and otherwise NULL.
137 * - packet->l7 to just past the TCP or UDP or ICMP header, if one is
138 * present and has a correct length, and otherwise NULL.
141 flow_extract(struct ofpbuf
*packet
, uint32_t tun_id
, uint16_t in_port
,
144 struct ofpbuf b
= *packet
;
145 struct eth_header
*eth
;
148 COVERAGE_INC(flow_extract
);
150 memset(flow
, 0, sizeof *flow
);
151 flow
->tun_id
= tun_id
;
152 flow
->in_port
= in_port
;
153 flow
->dl_vlan
= htons(OFP_VLAN_NONE
);
160 if (b
.size
< sizeof *eth
) {
166 memcpy(flow
->dl_src
, eth
->eth_src
, ETH_ADDR_LEN
);
167 memcpy(flow
->dl_dst
, eth
->eth_dst
, ETH_ADDR_LEN
);
169 /* dl_type, dl_vlan, dl_vlan_pcp. */
170 ofpbuf_pull(&b
, ETH_ADDR_LEN
* 2);
171 if (eth
->eth_type
== htons(ETH_TYPE_VLAN
)) {
172 parse_vlan(&b
, flow
);
174 flow
->dl_type
= parse_ethertype(&b
);
178 if (flow
->dl_type
== htons(ETH_TYPE_IP
)) {
179 const struct ip_header
*nh
= pull_ip(&b
);
181 flow
->nw_src
= get_unaligned_u32(&nh
->ip_src
);
182 flow
->nw_dst
= get_unaligned_u32(&nh
->ip_dst
);
183 flow
->nw_tos
= nh
->ip_tos
& IP_DSCP_MASK
;
184 flow
->nw_proto
= nh
->ip_proto
;
186 if (!IP_IS_FRAGMENT(nh
->ip_frag_off
)) {
187 if (flow
->nw_proto
== IP_TYPE_TCP
) {
188 const struct tcp_header
*tcp
= pull_tcp(&b
);
190 flow
->tp_src
= tcp
->tcp_src
;
191 flow
->tp_dst
= tcp
->tcp_dst
;
194 } else if (flow
->nw_proto
== IP_TYPE_UDP
) {
195 const struct udp_header
*udp
= pull_udp(&b
);
197 flow
->tp_src
= udp
->udp_src
;
198 flow
->tp_dst
= udp
->udp_dst
;
201 } else if (flow
->nw_proto
== IP_TYPE_ICMP
) {
202 const struct icmp_header
*icmp
= pull_icmp(&b
);
204 flow
->icmp_type
= htons(icmp
->icmp_type
);
205 flow
->icmp_code
= htons(icmp
->icmp_code
);
213 } else if (flow
->dl_type
== htons(ETH_TYPE_ARP
)) {
214 const struct arp_eth_header
*arp
= pull_arp(&b
);
215 if (arp
&& arp
->ar_hrd
== htons(1)
216 && arp
->ar_pro
== htons(ETH_TYPE_IP
)
217 && arp
->ar_hln
== ETH_ADDR_LEN
218 && arp
->ar_pln
== 4) {
219 /* We only match on the lower 8 bits of the opcode. */
220 if (ntohs(arp
->ar_op
) <= 0xff) {
221 flow
->nw_proto
= ntohs(arp
->ar_op
);
224 if ((flow
->nw_proto
== ARP_OP_REQUEST
)
225 || (flow
->nw_proto
== ARP_OP_REPLY
)) {
226 flow
->nw_src
= arp
->ar_spa
;
227 flow
->nw_dst
= arp
->ar_tpa
;
234 /* Extracts the flow stats for a packet. The 'flow' and 'packet'
235 * arguments must have been initialized through a call to flow_extract().
238 flow_extract_stats(const flow_t
*flow
, struct ofpbuf
*packet
,
239 struct odp_flow_stats
*stats
)
241 memset(stats
, '\0', sizeof(*stats
));
243 if ((flow
->dl_type
== htons(ETH_TYPE_IP
)) && packet
->l4
) {
244 if ((flow
->nw_proto
== IP_TYPE_TCP
) && packet
->l7
) {
245 struct tcp_header
*tcp
= packet
->l4
;
246 stats
->tcp_flags
= TCP_FLAGS(tcp
->tcp_ctl
);
250 stats
->n_bytes
= packet
->size
;
251 stats
->n_packets
= 1;
254 /* Extract 'flow' with 'wildcards' into the OpenFlow match structure
257 flow_to_match(const flow_t
*flow
, uint32_t wildcards
, bool tun_id_from_cookie
,
258 struct ofp_match
*match
)
260 if (!tun_id_from_cookie
) {
261 wildcards
&= OFPFW_ALL
;
263 match
->wildcards
= htonl(wildcards
);
265 match
->in_port
= htons(flow
->in_port
== ODPP_LOCAL
? OFPP_LOCAL
267 match
->dl_vlan
= flow
->dl_vlan
;
268 match
->dl_vlan_pcp
= flow
->dl_vlan_pcp
;
269 memcpy(match
->dl_src
, flow
->dl_src
, ETH_ADDR_LEN
);
270 memcpy(match
->dl_dst
, flow
->dl_dst
, ETH_ADDR_LEN
);
271 match
->dl_type
= flow
->dl_type
;
272 match
->nw_src
= flow
->nw_src
;
273 match
->nw_dst
= flow
->nw_dst
;
274 match
->nw_tos
= flow
->nw_tos
;
275 match
->nw_proto
= flow
->nw_proto
;
276 match
->tp_src
= flow
->tp_src
;
277 match
->tp_dst
= flow
->tp_dst
;
278 memset(match
->pad1
, '\0', sizeof match
->pad1
);
279 memset(match
->pad2
, '\0', sizeof match
->pad2
);
283 flow_from_match(const struct ofp_match
*match
, bool tun_id_from_cookie
,
284 uint64_t cookie
, flow_t
*flow
, uint32_t *flow_wildcards
)
286 uint32_t wildcards
= ntohl(match
->wildcards
);
288 flow
->nw_src
= match
->nw_src
;
289 flow
->nw_dst
= match
->nw_dst
;
290 if (tun_id_from_cookie
&& !(wildcards
& NXFW_TUN_ID
)) {
291 flow
->tun_id
= htonl(ntohll(cookie
) >> 32);
293 wildcards
|= NXFW_TUN_ID
;
296 flow
->in_port
= (match
->in_port
== htons(OFPP_LOCAL
) ? ODPP_LOCAL
297 : ntohs(match
->in_port
));
298 flow
->dl_vlan
= match
->dl_vlan
;
299 flow
->dl_vlan_pcp
= match
->dl_vlan_pcp
;
300 flow
->dl_type
= match
->dl_type
;
301 flow
->tp_src
= match
->tp_src
;
302 flow
->tp_dst
= match
->tp_dst
;
303 memcpy(flow
->dl_src
, match
->dl_src
, ETH_ADDR_LEN
);
304 memcpy(flow
->dl_dst
, match
->dl_dst
, ETH_ADDR_LEN
);
305 flow
->nw_tos
= match
->nw_tos
;
306 flow
->nw_proto
= match
->nw_proto
;
307 memset(flow
->reserved
, 0, sizeof flow
->reserved
);
309 if (flow_wildcards
) {
310 *flow_wildcards
= wildcards
;
315 flow_to_string(const flow_t
*flow
)
317 struct ds ds
= DS_EMPTY_INITIALIZER
;
318 flow_format(&ds
, flow
);
323 flow_format(struct ds
*ds
, const flow_t
*flow
)
325 ds_put_format(ds
, "tunnel%08"PRIx32
":in_port%04"PRIx16
326 ":vlan%"PRIu16
":pcp%"PRIu8
327 " mac"ETH_ADDR_FMT
"->"ETH_ADDR_FMT
331 " ip"IP_FMT
"->"IP_FMT
332 " port%"PRIu16
"->%"PRIu16
,
335 ntohs(flow
->dl_vlan
),
337 ETH_ADDR_ARGS(flow
->dl_src
),
338 ETH_ADDR_ARGS(flow
->dl_dst
),
339 ntohs(flow
->dl_type
),
342 IP_ARGS(&flow
->nw_src
),
343 IP_ARGS(&flow
->nw_dst
),
345 ntohs(flow
->tp_dst
));
349 flow_print(FILE *stream
, const flow_t
*flow
)
351 char *s
= flow_to_string(flow
);