]>
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"
32 #define THIS_MODULE VLM_flow
34 static struct arp_eth_header
*
35 pull_arp(struct ofpbuf
*packet
)
37 return ofpbuf_try_pull(packet
, ARP_ETH_HEADER_LEN
);
40 static struct ip_header
*
41 pull_ip(struct ofpbuf
*packet
)
43 if (packet
->size
>= IP_HEADER_LEN
) {
44 struct ip_header
*ip
= packet
->data
;
45 int ip_len
= IP_IHL(ip
->ip_ihl_ver
) * 4;
46 if (ip_len
>= IP_HEADER_LEN
&& packet
->size
>= ip_len
) {
47 return ofpbuf_pull(packet
, ip_len
);
53 static struct tcp_header
*
54 pull_tcp(struct ofpbuf
*packet
)
56 if (packet
->size
>= TCP_HEADER_LEN
) {
57 struct tcp_header
*tcp
= packet
->data
;
58 int tcp_len
= TCP_OFFSET(tcp
->tcp_ctl
) * 4;
59 if (tcp_len
>= TCP_HEADER_LEN
&& packet
->size
>= tcp_len
) {
60 return ofpbuf_pull(packet
, tcp_len
);
66 static struct udp_header
*
67 pull_udp(struct ofpbuf
*packet
)
69 return ofpbuf_try_pull(packet
, UDP_HEADER_LEN
);
72 static struct icmp_header
*
73 pull_icmp(struct ofpbuf
*packet
)
75 return ofpbuf_try_pull(packet
, ICMP_HEADER_LEN
);
78 static struct eth_header
*
79 pull_eth(struct ofpbuf
*packet
)
81 return ofpbuf_try_pull(packet
, ETH_HEADER_LEN
);
84 static struct vlan_header
*
85 pull_vlan(struct ofpbuf
*packet
)
87 return ofpbuf_try_pull(packet
, VLAN_HEADER_LEN
);
90 /* Returns 1 if 'packet' is an IP fragment, 0 otherwise. */
92 flow_extract(struct ofpbuf
*packet
, uint16_t in_port
, flow_t
*flow
)
94 struct ofpbuf b
= *packet
;
95 struct eth_header
*eth
;
98 COVERAGE_INC(flow_extract
);
100 memset(flow
, 0, sizeof *flow
);
101 flow
->dl_vlan
= htons(OFP_VLAN_NONE
);
102 flow
->in_port
= in_port
;
111 if (ntohs(eth
->eth_type
) >= OFP_DL_TYPE_ETH2_CUTOFF
) {
112 /* This is an Ethernet II frame */
113 flow
->dl_type
= eth
->eth_type
;
115 /* This is an 802.2 frame */
116 struct llc_header
*llc
= ofpbuf_at(&b
, 0, sizeof *llc
);
117 struct snap_header
*snap
= ofpbuf_at(&b
, sizeof *llc
,
123 && llc
->llc_dsap
== LLC_DSAP_SNAP
124 && llc
->llc_ssap
== LLC_SSAP_SNAP
125 && llc
->llc_cntl
== LLC_CNTL_SNAP
126 && !memcmp(snap
->snap_org
, SNAP_ORG_ETHERNET
,
127 sizeof snap
->snap_org
)) {
128 flow
->dl_type
= snap
->snap_type
;
129 ofpbuf_pull(&b
, LLC_SNAP_HEADER_LEN
);
131 flow
->dl_type
= htons(OFP_DL_TYPE_NOT_ETH_TYPE
);
132 ofpbuf_pull(&b
, sizeof(struct llc_header
));
136 /* Check for a VLAN tag */
137 if (flow
->dl_type
== htons(ETH_TYPE_VLAN
)) {
138 struct vlan_header
*vh
= pull_vlan(&b
);
140 flow
->dl_type
= vh
->vlan_next_type
;
141 flow
->dl_vlan
= vh
->vlan_tci
& htons(VLAN_VID_MASK
);
142 flow
->dl_vlan_pcp
= (ntohs(vh
->vlan_tci
) & 0xe000) >> 13;
145 memcpy(flow
->dl_src
, eth
->eth_src
, ETH_ADDR_LEN
);
146 memcpy(flow
->dl_dst
, eth
->eth_dst
, ETH_ADDR_LEN
);
149 if (flow
->dl_type
== htons(ETH_TYPE_IP
)) {
150 const struct ip_header
*nh
= pull_ip(&b
);
152 flow
->nw_src
= nh
->ip_src
;
153 flow
->nw_dst
= nh
->ip_dst
;
154 flow
->nw_tos
= nh
->ip_tos
& 0xfc;
155 flow
->nw_proto
= nh
->ip_proto
;
157 if (!IP_IS_FRAGMENT(nh
->ip_frag_off
)) {
158 if (flow
->nw_proto
== IP_TYPE_TCP
) {
159 const struct tcp_header
*tcp
= pull_tcp(&b
);
161 flow
->tp_src
= tcp
->tcp_src
;
162 flow
->tp_dst
= tcp
->tcp_dst
;
165 /* Avoid tricking other code into thinking that
166 * this packet has an L4 header. */
169 } else if (flow
->nw_proto
== IP_TYPE_UDP
) {
170 const struct udp_header
*udp
= pull_udp(&b
);
172 flow
->tp_src
= udp
->udp_src
;
173 flow
->tp_dst
= udp
->udp_dst
;
176 /* Avoid tricking other code into thinking that
177 * this packet has an L4 header. */
180 } else if (flow
->nw_proto
== IP_TYPE_ICMP
) {
181 const struct icmp_header
*icmp
= pull_icmp(&b
);
183 flow
->icmp_type
= htons(icmp
->icmp_type
);
184 flow
->icmp_code
= htons(icmp
->icmp_code
);
187 /* Avoid tricking other code into thinking that
188 * this packet has an L4 header. */
196 } else if (flow
->dl_type
== htons(ETH_TYPE_ARP
)) {
197 const struct arp_eth_header
*arp
= pull_arp(&b
);
198 if (arp
&& arp
->ar_hrd
== htons(1)
199 && arp
->ar_pro
== htons(ETH_TYPE_IP
)
200 && arp
->ar_hln
== ETH_ADDR_LEN
201 && arp
->ar_pln
== 4) {
202 /* We only match on the lower 8 bits of the opcode. */
203 if (ntohs(arp
->ar_op
) <= 0xff) {
204 flow
->nw_proto
= ntohs(arp
->ar_op
);
207 if ((flow
->nw_proto
== ARP_OP_REQUEST
)
208 || (flow
->nw_proto
== ARP_OP_REPLY
)) {
209 flow
->nw_src
= arp
->ar_spa
;
210 flow
->nw_dst
= arp
->ar_tpa
;
218 /* Extracts the flow stats for a packet. The 'flow' and 'packet'
219 * arguments must have been initialized through a call to flow_extract().
222 flow_extract_stats(const flow_t
*flow
, struct ofpbuf
*packet
,
223 struct odp_flow_stats
*stats
)
225 memset(stats
, '\0', sizeof(*stats
));
227 if ((flow
->dl_type
== htons(ETH_TYPE_IP
)) && packet
->l4
) {
228 struct ip_header
*ip
= packet
->l3
;
229 stats
->ip_tos
= ip
->ip_tos
;
230 if ((flow
->nw_proto
== IP_TYPE_TCP
) && packet
->l7
) {
231 struct tcp_header
*tcp
= packet
->l4
;
232 stats
->tcp_flags
= TCP_FLAGS(tcp
->tcp_ctl
);
236 stats
->n_bytes
= packet
->size
;
237 stats
->n_packets
= 1;
240 /* Extract 'flow' with 'wildcards' into the OpenFlow match structure
243 flow_to_match(const flow_t
*flow
, uint32_t wildcards
, struct ofp_match
*match
)
245 match
->wildcards
= htonl(wildcards
);
246 match
->in_port
= htons(flow
->in_port
== ODPP_LOCAL
? OFPP_LOCAL
248 match
->dl_vlan
= flow
->dl_vlan
;
249 match
->dl_vlan_pcp
= flow
->dl_vlan_pcp
;
250 memcpy(match
->dl_src
, flow
->dl_src
, ETH_ADDR_LEN
);
251 memcpy(match
->dl_dst
, flow
->dl_dst
, ETH_ADDR_LEN
);
252 match
->dl_type
= flow
->dl_type
;
253 match
->nw_src
= flow
->nw_src
;
254 match
->nw_dst
= flow
->nw_dst
;
255 match
->nw_tos
= flow
->nw_tos
;
256 match
->nw_proto
= flow
->nw_proto
;
257 match
->tp_src
= flow
->tp_src
;
258 match
->tp_dst
= flow
->tp_dst
;
259 memset(match
->pad1
, '\0', sizeof match
->pad1
);
260 memset(match
->pad2
, '\0', sizeof match
->pad2
);
264 flow_from_match(flow_t
*flow
, uint32_t *wildcards
,
265 const struct ofp_match
*match
)
268 *wildcards
= ntohl(match
->wildcards
);
270 flow
->nw_src
= match
->nw_src
;
271 flow
->nw_dst
= match
->nw_dst
;
272 flow
->in_port
= (match
->in_port
== htons(OFPP_LOCAL
) ? ODPP_LOCAL
273 : ntohs(match
->in_port
));
274 flow
->dl_vlan
= match
->dl_vlan
;
275 flow
->dl_vlan_pcp
= match
->dl_vlan_pcp
;
276 flow
->dl_type
= match
->dl_type
;
277 flow
->tp_src
= match
->tp_src
;
278 flow
->tp_dst
= match
->tp_dst
;
279 memcpy(flow
->dl_src
, match
->dl_src
, ETH_ADDR_LEN
);
280 memcpy(flow
->dl_dst
, match
->dl_dst
, ETH_ADDR_LEN
);
281 flow
->nw_tos
= match
->nw_tos
;
282 flow
->nw_proto
= match
->nw_proto
;
283 memset(flow
->reserved
, 0, sizeof flow
->reserved
);
287 flow_to_string(const flow_t
*flow
)
289 struct ds ds
= DS_EMPTY_INITIALIZER
;
290 flow_format(&ds
, flow
);
295 flow_format(struct ds
*ds
, const flow_t
*flow
)
297 ds_put_format(ds
, "in_port%04x:vlan%d:pcp%d mac"ETH_ADDR_FMT
298 "->"ETH_ADDR_FMT
" type%04x proto%"PRId8
" tos%"PRIu8
299 " ip"IP_FMT
"->"IP_FMT
" port%d->%d",
300 flow
->in_port
, ntohs(flow
->dl_vlan
), flow
->dl_vlan_pcp
,
301 ETH_ADDR_ARGS(flow
->dl_src
), ETH_ADDR_ARGS(flow
->dl_dst
),
302 ntohs(flow
->dl_type
), flow
->nw_proto
, flow
->nw_tos
,
303 IP_ARGS(&flow
->nw_src
), IP_ARGS(&flow
->nw_dst
),
304 ntohs(flow
->tp_src
), ntohs(flow
->tp_dst
));
308 flow_print(FILE *stream
, const flow_t
*flow
)
310 char *s
= flow_to_string(flow
);