X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=datapath%2Fflow.c;h=ae60617dd27e08a167e6735420a603e580af51c9;hb=837e80977cdd9fda61fb0789bfd6b64c7639c25a;hp=2ac79e70fe449e1b8d507f5051940ee468a9a3d1;hpb=a14bc59fb8f27db193d74662dc9c5cb8237177ef;p=openvswitch diff --git a/datapath/flow.c b/datapath/flow.c index 2ac79e70..ae60617d 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,27 @@ struct kmem_cache *flow_cache; +struct arp_eth_header +{ + __be16 ar_hrd; /* format of hardware address */ + __be16 ar_pro; /* format of protocol address */ + unsigned char ar_hln; /* length of hardware address */ + unsigned char ar_pln; /* length of protocol address */ + __be16 ar_op; /* ARP opcode (command) */ + + /* Ethernet+IPv4 specific members. */ + unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ + unsigned char ar_sip[4]; /* sender IP address */ + unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ + unsigned char ar_tip[4]; /* target IP address */ +} __attribute__((packed)); + +static inline int arphdr_ok(struct sk_buff *skb) +{ + int nh_ofs = skb_network_offset(skb); + return pskb_may_pull(skb, nh_ofs + sizeof(struct arp_eth_header)); +} + static inline int iphdr_ok(struct sk_buff *skb) { int nh_ofs = skb_network_offset(skb); @@ -266,6 +288,27 @@ int flow_extract(struct sk_buff *skb, u16 in_port, struct odp_flow_key *key) } else { retval = 1; } + } else if (key->dl_type == htons(ETH_P_ARP) && arphdr_ok(skb)) { + struct arp_eth_header *arp; + + arp = (struct arp_eth_header *)skb_network_header(skb); + + if (arp->ar_hrd == htons(1) + && arp->ar_pro == htons(ETH_P_IP) + && arp->ar_hln == ETH_ALEN + && arp->ar_pln == 4) { + + /* We only match on the lower 8 bits of the opcode. */ + if (ntohs(arp->ar_op) <= 0xff) { + key->nw_proto = ntohs(arp->ar_op); + } + + if (key->nw_proto == ARPOP_REQUEST + || key->nw_proto == ARPOP_REPLY) { + memcpy(&key->nw_src, arp->ar_sip, sizeof(key->nw_src)); + memcpy(&key->nw_dst, arp->ar_tip, sizeof(key->nw_dst)); + } + } } else { skb_reset_transport_header(skb); }