4 #include <netinet/in.h>
14 #define THIS_MODULE VLM_flow
17 flow_extract(struct buffer *packet, uint16_t in_port, struct flow *flow)
19 struct buffer b = *packet;
20 struct eth_header *eth;
22 if (b.size < ETH_TOTAL_MIN) {
23 VLOG_WARN("packet length %d less than minimum size %d",
24 b.size, ETH_TOTAL_MIN);
27 memset(flow, 0, sizeof *flow);
28 flow->in_port = htons(in_port);
34 eth = buffer_at(&b, 0, sizeof *eth);
36 buffer_pull(&b, ETH_HEADER_LEN);
37 if (ntohs(eth->eth_type) >= OFP_DL_TYPE_ETH2_CUTOFF) {
38 /* This is an Ethernet II frame */
39 flow->dl_type = eth->eth_type;
41 /* This is an 802.2 frame */
42 struct llc_snap_header *h = buffer_at(&b, 0, sizeof *h);
46 if (h->llc.llc_dsap == LLC_DSAP_SNAP
47 && h->llc.llc_ssap == LLC_SSAP_SNAP
48 && h->llc.llc_cntl == LLC_CNTL_SNAP
49 && !memcmp(h->snap.snap_org, SNAP_ORG_ETHERNET,
50 sizeof h->snap.snap_org)) {
51 flow->dl_type = h->snap.snap_type;
52 buffer_pull(&b, sizeof *h);
54 flow->dl_type = OFP_DL_TYPE_NOT_ETH_TYPE;
55 buffer_pull(&b, sizeof(struct llc_header));
59 /* Check for a VLAN tag */
60 if (flow->dl_type != htons(ETH_TYPE_VLAN)) {
61 flow->dl_vlan = htons(OFP_VLAN_NONE);
63 struct vlan_header *vh = buffer_at(&b, 0, sizeof *vh);
64 flow->dl_type = vh->vlan_next_type;
65 flow->dl_vlan = vh->vlan_tci & htons(VLAN_VID);
66 buffer_pull(&b, sizeof *vh);
68 memcpy(flow->dl_src, eth->eth_src, ETH_ADDR_LEN);
69 memcpy(flow->dl_dst, eth->eth_dst, ETH_ADDR_LEN);
72 if (flow->dl_type == htons(ETH_TYPE_IP)) {
73 const struct ip_header *nh = buffer_at(&b, 0, sizeof *nh);
75 int ip_len = IP_IHL(nh->ip_ihl_ver) * 4;
76 if (ip_len < IP_HEADER_LEN) {
80 flow->nw_src = nh->ip_src;
81 flow->nw_dst = nh->ip_dst;
82 flow->nw_proto = nh->ip_proto;
83 if (flow->nw_proto == IP_TYPE_TCP
84 || flow->nw_proto == IP_TYPE_UDP) {
85 const struct udp_header *th;
86 th = packet->l4 = buffer_at(&b, ip_len, sizeof *th);
88 flow->tp_src = th->udp_src;
89 flow->tp_dst = th->udp_dst;
91 /* Avoid tricking other code into thinking that this
92 * packet has an L4 header. */
97 } else if (flow->dl_type == htons(ETH_TYPE_ARP)) {
98 const struct arp_eth_header *ah = buffer_at(&b, 0, sizeof *ah);
99 if (ah && ah->ar_hrd == htons(ARP_HRD_ETHERNET)
100 && ah->ar_pro == htons(ARP_PRO_IP)
101 && ah->ar_hln == ETH_ADDR_LEN
102 && ah->ar_pln == sizeof flow->nw_src)
104 /* check if sha/tha match dl_src/dl_dst? */
105 flow->nw_src = ah->ar_spa;
106 flow->nw_dst = ah->ar_tpa;
113 flow_print(FILE *stream, const struct flow *flow)
116 "port%04x:vlan%04x mac"MAC_FMT"->"MAC_FMT" "
117 "proto%04x ip"IP_FMT"->"IP_FMT" port%d->%d",
118 ntohs(flow->in_port), ntohs(flow->dl_vlan),
119 MAC_ARGS(flow->dl_src), MAC_ARGS(flow->dl_dst),
120 ntohs(flow->dl_type),
121 IP_ARGS(&flow->nw_src), IP_ARGS(&flow->nw_dst),
122 ntohs(flow->tp_src), ntohs(flow->tp_dst));
126 flow_compare(const struct flow *a, const struct flow *b)
128 return memcmp(a, b, sizeof *a);
132 flow_hash(const struct flow *flow, uint32_t basis)
134 return hash_fnv(flow, sizeof *flow, basis);