Initial import
[openvswitch] / lib / flow.c
1 #include <sys/types.h>
2 #include "flow.h"
3 #include <inttypes.h>
4 #include <netinet/in.h>
5 #include <string.h>
6 #include "buffer.h"
7 #include "hash.h"
8 #include "ip.h"
9 #include "mac.h"
10 #include "openflow.h"
11 #include "packets.h"
12
13 #include "vlog.h"
14 #define THIS_MODULE VLM_flow
15
16 void
17 flow_extract(const struct buffer *packet, uint16_t in_port, struct flow *flow)
18 {
19     struct buffer b = *packet;
20     struct eth_header *eth;
21
22     if (b.size < ETH_TOTAL_MIN) {
23         VLOG_WARN("packet length %d less than minimum size %d",
24                   b.size, ETH_TOTAL_MIN);
25     }
26
27     memset(flow, 0, sizeof *flow);
28     flow->in_port = htons(in_port);
29
30     eth = buffer_at(&b, 0, sizeof *eth);
31     if (eth) {
32         buffer_pull(&b, ETH_HEADER_LEN);
33         if (ntohs(eth->eth_type) >= OFP_DL_TYPE_ETH2_CUTOFF) {
34             /* This is an Ethernet II frame */
35             flow->dl_type = eth->eth_type;
36         } else {
37             /* This is an 802.2 frame */
38             struct llc_snap_header *h = buffer_at(&b, 0, sizeof *h);
39             if (h == NULL) {
40                 return;
41             }
42             if (h->llc.llc_dsap == LLC_DSAP_SNAP
43                 && h->llc.llc_ssap == LLC_SSAP_SNAP
44                 && h->llc.llc_cntl == LLC_CNTL_SNAP
45                 && !memcmp(h->snap.snap_org, SNAP_ORG_ETHERNET,
46                            sizeof h->snap.snap_org)) {
47                 flow->dl_type = h->snap.snap_type;
48                 buffer_pull(&b, sizeof *h);
49             } else {
50                 flow->dl_type = OFP_DL_TYPE_NOT_ETH_TYPE;
51                 buffer_pull(&b, sizeof(struct llc_header));
52             }
53         }
54
55         /* Check for a VLAN tag */
56         if (flow->dl_type != htons(ETH_TYPE_VLAN)) {
57             flow->dl_vlan = htons(OFP_VLAN_NONE);
58         } else {
59             struct vlan_header *vh = buffer_at(&b, 0, sizeof *vh);
60             flow->dl_type = vh->vlan_next_type;
61             flow->dl_vlan = vh->vlan_tci & htons(VLAN_VID);
62             buffer_pull(&b, sizeof *vh);
63         }
64         memcpy(flow->dl_src, eth->eth_src, ETH_ADDR_LEN);
65         memcpy(flow->dl_dst, eth->eth_dst, ETH_ADDR_LEN);
66
67         if (flow->dl_type == htons(ETH_TYPE_IP)) {
68             const struct ip_header *nh = buffer_at(&b, 0, sizeof *nh);
69             if (nh) {
70                 flow->nw_src = nh->ip_src;
71                 flow->nw_dst = nh->ip_dst;
72                 flow->nw_proto = nh->ip_proto;
73                 if (flow->nw_proto == IP_TYPE_TCP
74                     || flow->nw_proto == IP_TYPE_UDP) {
75                     int udp_ofs = IP_IHL(nh->ip_ihl_ver) * 4;
76                     const struct udp_header *th
77                         = buffer_at(&b, udp_ofs, sizeof *th);
78                     if (th) {
79                         flow->tp_src = th->udp_src;
80                         flow->tp_dst = th->udp_dst;
81                     }
82                 }
83             }
84         } else if (flow->dl_type == htons(ETH_TYPE_ARP)) {
85             const struct arp_eth_header *ah = buffer_at(&b, 0, sizeof *ah);
86             if (ah && ah->ar_hrd == htons(ARP_HRD_ETHERNET)
87                 && ah->ar_pro == htons(ARP_PRO_IP)
88                 && ah->ar_hln == ETH_ADDR_LEN
89                 && ah->ar_pln == sizeof flow->nw_src)
90             {
91                 /* check if sha/tha match dl_src/dl_dst? */
92                 flow->nw_src = ah->ar_spa;
93                 flow->nw_dst = ah->ar_tpa;
94             }
95         }
96     }
97 }
98
99 void
100 flow_print(FILE *stream, const struct flow *flow) 
101 {
102     fprintf(stream,
103             "port%04x:vlan%04x mac"MAC_FMT"->"MAC_FMT" "
104             "proto%04x ip"IP_FMT"->"IP_FMT" port%d->%d",
105             ntohs(flow->in_port), ntohs(flow->dl_vlan),
106             MAC_ARGS(flow->dl_src), MAC_ARGS(flow->dl_dst),
107             ntohs(flow->dl_type),
108             IP_ARGS(&flow->nw_src), IP_ARGS(&flow->nw_dst),
109             ntohs(flow->tp_src), ntohs(flow->tp_dst));
110 }
111
112 int
113 flow_compare(const struct flow *a, const struct flow *b)
114 {
115     return memcmp(a, b, sizeof *a);
116 }
117
118 unsigned long int
119 flow_hash(const struct flow *flow, uint32_t basis) 
120 {
121     return hash_fnv(flow, sizeof *flow, basis);
122 }