Add support for connection tracking.
[cascardo/ovs.git] / lib / packets.c
index 419c6af..2915c74 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@
 #include "unaligned.h"
 
 const struct in6_addr in6addr_exact = IN6ADDR_EXACT_INIT;
+const struct in6_addr in6addr_all_hosts = IN6ADDR_ALL_HOSTS_INIT;
 
 /* Parses 's' as a 16-digit hexadecimal number representing a datapath ID.  On
  * success stores the dpid into '*dpidp' and returns true, on failure stores 0
@@ -55,7 +56,7 @@ dpid_from_string(const char *s, uint64_t *dpidp)
  * If you change this function's behavior, please update corresponding
  * documentation in vswitch.xml at the same time. */
 bool
-eth_addr_is_reserved(const uint8_t ea[ETH_ADDR_LEN])
+eth_addr_is_reserved(const struct eth_addr ea)
 {
     struct eth_addr_node {
         struct hmap_node hmap_node;
@@ -128,12 +129,12 @@ eth_addr_is_reserved(const uint8_t ea[ETH_ADDR_LEN])
 }
 
 bool
-eth_addr_from_string(const char *s, uint8_t ea[ETH_ADDR_LEN])
+eth_addr_from_string(const char *s, struct eth_addr *ea)
 {
-    if (ovs_scan(s, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(ea))) {
+    if (ovs_scan(s, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(*ea))) {
         return true;
     } else {
-        memset(ea, 0, ETH_ADDR_LEN);
+        *ea = eth_addr_zero;
         return false;
     }
 }
@@ -145,7 +146,7 @@ eth_addr_from_string(const char *s, uint8_t ea[ETH_ADDR_LEN])
  * The returned packet has enough headroom to insert an 802.1Q VLAN header if
  * desired. */
 void
-compose_rarp(struct dp_packet *b, const uint8_t eth_src[ETH_ADDR_LEN])
+compose_rarp(struct dp_packet *b, const struct eth_addr eth_src)
 {
     struct eth_header *eth;
     struct arp_eth_header *arp;
@@ -155,8 +156,8 @@ compose_rarp(struct dp_packet *b, const uint8_t eth_src[ETH_ADDR_LEN])
                              + ARP_ETH_HEADER_LEN);
     dp_packet_reserve(b, 2 + VLAN_HEADER_LEN);
     eth = dp_packet_put_uninit(b, sizeof *eth);
-    memcpy(eth->eth_dst, eth_addr_broadcast, ETH_ADDR_LEN);
-    memcpy(eth->eth_src, eth_src, ETH_ADDR_LEN);
+    eth->eth_dst = eth_addr_broadcast;
+    eth->eth_src = eth_src;
     eth->eth_type = htons(ETH_TYPE_RARP);
 
     arp = dp_packet_put_uninit(b, sizeof *arp);
@@ -165,12 +166,12 @@ compose_rarp(struct dp_packet *b, const uint8_t eth_src[ETH_ADDR_LEN])
     arp->ar_hln = sizeof arp->ar_sha;
     arp->ar_pln = sizeof arp->ar_spa;
     arp->ar_op = htons(ARP_OP_RARP);
-    memcpy(arp->ar_sha, eth_src, ETH_ADDR_LEN);
+    arp->ar_sha = eth_src;
     put_16aligned_be32(&arp->ar_spa, htonl(0));
-    memcpy(arp->ar_tha, eth_src, ETH_ADDR_LEN);
+    arp->ar_tha = eth_src;
     put_16aligned_be32(&arp->ar_tpa, htonl(0));
 
-    dp_packet_set_frame(b, eth);
+    dp_packet_reset_offsets(b);
     dp_packet_set_l3(b, arp);
 }
 
@@ -192,15 +193,15 @@ eth_push_vlan(struct dp_packet *packet, ovs_be16 tpid, ovs_be16 tci)
 
 /* Removes outermost VLAN header (if any is present) from 'packet'.
  *
- * 'packet->l2_5' should initially point to 'packet''s outer-most MPLS header
- * or may be NULL if there are no MPLS headers. */
+ * 'packet->l2_5' should initially point to 'packet''s outer-most VLAN header
+ * or may be NULL if there are no VLAN headers. */
 void
 eth_pop_vlan(struct dp_packet *packet)
 {
     struct vlan_eth_header *veh = dp_packet_l2(packet);
 
     if (veh && dp_packet_size(packet) >= sizeof *veh
-        && veh->veth_type == htons(ETH_TYPE_VLAN)) {
+        && eth_type_vlan(veh->veth_type)) {
 
         memmove((char *)veh + VLAN_HEADER_LEN, veh, 2 * ETH_ADDR_LEN);
         dp_packet_resize_l2(packet, -VLAN_HEADER_LEN);
@@ -217,7 +218,7 @@ set_ethertype(struct dp_packet *packet, ovs_be16 eth_type)
         return;
     }
 
-    if (eh->eth_type == htons(ETH_TYPE_VLAN)) {
+    if (eth_type_vlan(eh->eth_type)) {
         ovs_be16 *p;
         char *l2_5 = dp_packet_l2_5(packet);
 
@@ -293,7 +294,7 @@ set_mpls_lse(struct dp_packet *packet, ovs_be32 mpls_lse)
     }
 }
 
-/* Push MPLS label stack entry 'lse' onto 'packet' as the the outermost MPLS
+/* Push MPLS label stack entry 'lse' onto 'packet' as the outermost MPLS
  * header.  If 'packet' does not already have any MPLS labels, then its
  * Ethertype is changed to 'ethtype' (which must be an MPLS Ethertype). */
 void
@@ -370,24 +371,12 @@ eth_from_hex(const char *hex, struct dp_packet **packetp)
 }
 
 void
-eth_format_masked(const uint8_t eth[ETH_ADDR_LEN],
-                  const uint8_t mask[ETH_ADDR_LEN], struct ds *s)
+eth_format_masked(const struct eth_addr eth,
+                  const struct eth_addr *mask, struct ds *s)
 {
     ds_put_format(s, ETH_ADDR_FMT, ETH_ADDR_ARGS(eth));
-    if (mask && !eth_mask_is_exact(mask)) {
-        ds_put_format(s, "/"ETH_ADDR_FMT, ETH_ADDR_ARGS(mask));
-    }
-}
-
-void
-eth_addr_bitand(const uint8_t src[ETH_ADDR_LEN],
-                const uint8_t mask[ETH_ADDR_LEN],
-                uint8_t dst[ETH_ADDR_LEN])
-{
-    int i;
-
-    for (i = 0; i < ETH_ADDR_LEN; i++) {
-        dst[i] = src[i] & mask[i];
+    if (mask && !eth_mask_is_exact(*mask)) {
+        ds_put_format(s, "/"ETH_ADDR_FMT, ETH_ADDR_ARGS(*mask));
     }
 }
 
@@ -437,6 +426,17 @@ print_ipv6_addr(struct ds *string, const struct in6_addr *addr)
     string->length += strlen(dst);
 }
 
+void
+print_ipv6_mapped(struct ds *s, const struct in6_addr *addr)
+{
+    if (IN6_IS_ADDR_V4MAPPED(addr)) {
+        ds_put_format(s, IP_FMT, addr->s6_addr[12], addr->s6_addr[13],
+                                 addr->s6_addr[14], addr->s6_addr[15]);
+    } else {
+        print_ipv6_addr(s, addr);
+    }
+}
+
 void
 print_ipv6_masked(struct ds *s, const struct in6_addr *addr,
                   const struct in6_addr *mask)
@@ -559,8 +559,8 @@ ipv6_is_cidr(const struct in6_addr *netmask)
  * The returned packet has enough headroom to insert an 802.1Q VLAN header if
  * desired. */
 void *
-eth_compose(struct dp_packet *b, const uint8_t eth_dst[ETH_ADDR_LEN],
-            const uint8_t eth_src[ETH_ADDR_LEN], uint16_t eth_type,
+eth_compose(struct dp_packet *b, const struct eth_addr eth_dst,
+            const struct eth_addr eth_src, uint16_t eth_type,
             size_t size)
 {
     void *data;
@@ -575,11 +575,11 @@ eth_compose(struct dp_packet *b, const uint8_t eth_dst[ETH_ADDR_LEN],
     eth = dp_packet_put_uninit(b, ETH_HEADER_LEN);
     data = dp_packet_put_uninit(b, size);
 
-    memcpy(eth->eth_dst, eth_dst, ETH_ADDR_LEN);
-    memcpy(eth->eth_src, eth_src, ETH_ADDR_LEN);
+    eth->eth_dst = eth_dst;
+    eth->eth_src = eth_src;
     eth->eth_type = htons(eth_type);
 
-    dp_packet_set_frame(b, eth);
+    dp_packet_reset_offsets(b);
     dp_packet_set_l3(b, data);
 
     return data;
@@ -877,8 +877,7 @@ packet_set_sctp_port(struct dp_packet *packet, ovs_be16 src, ovs_be16 dst)
 
 void
 packet_set_nd(struct dp_packet *packet, const ovs_be32 target[4],
-              const uint8_t sll[ETH_ADDR_LEN],
-              const uint8_t tll[ETH_ADDR_LEN]) {
+              const struct eth_addr sll, const struct eth_addr tll) {
     struct ovs_nd_msg *ns;
     struct ovs_nd_opt *nd_opt;
     int bytes_remain = dp_packet_l4_size(packet);
@@ -900,22 +899,22 @@ packet_set_nd(struct dp_packet *packet, const ovs_be32 target[4],
     while (bytes_remain >= ND_OPT_LEN && nd_opt->nd_opt_len != 0) {
         if (nd_opt->nd_opt_type == ND_OPT_SOURCE_LINKADDR
             && nd_opt->nd_opt_len == 1) {
-            if (memcmp(nd_opt->nd_opt_data, sll, ETH_ADDR_LEN)) {
+            if (!eth_addr_equals(nd_opt->nd_opt_mac, sll)) {
                 ovs_be16 *csum = &(ns->icmph.icmp6_cksum);
 
-                *csum = recalc_csum48(*csum, nd_opt->nd_opt_data, sll);
-                memcpy(nd_opt->nd_opt_data, sll, ETH_ADDR_LEN);
+                *csum = recalc_csum48(*csum, nd_opt->nd_opt_mac, sll);
+                nd_opt->nd_opt_mac = sll;
             }
 
             /* A packet can only contain one SLL or TLL option */
             break;
         } else if (nd_opt->nd_opt_type == ND_OPT_TARGET_LINKADDR
                    && nd_opt->nd_opt_len == 1) {
-            if (memcmp(nd_opt->nd_opt_data, tll, ETH_ADDR_LEN)) {
+            if (!eth_addr_equals(nd_opt->nd_opt_mac, tll)) {
                 ovs_be16 *csum = &(ns->icmph.icmp6_cksum);
 
-                *csum = recalc_csum48(*csum, nd_opt->nd_opt_data, tll);
-                memcpy(nd_opt->nd_opt_data, tll, ETH_ADDR_LEN);
+                *csum = recalc_csum48(*csum, nd_opt->nd_opt_mac, tll);
+                nd_opt->nd_opt_mac = tll;
             }
 
             /* A packet can only contain one SLL or TLL option */
@@ -1012,9 +1011,15 @@ packet_format_tcp_flags(struct ds *s, uint16_t tcp_flags)
 #define ARP_PACKET_SIZE  (2 + ETH_HEADER_LEN + VLAN_HEADER_LEN + \
                           ARP_ETH_HEADER_LEN)
 
+/* Clears 'b' and replaces its contents by an ARP frame with the specified
+ * 'arp_op', 'arp_sha', 'arp_tha', 'arp_spa', and 'arp_tpa'.  The outer
+ * Ethernet frame is initialized with Ethernet source 'arp_sha' and destination
+ * 'arp_tha', except that destination ff:ff:ff:ff:ff:ff is used instead if
+ * 'broadcast' is true. */
 void
-compose_arp(struct dp_packet *b, const uint8_t eth_src[ETH_ADDR_LEN],
-            ovs_be32 ip_src, ovs_be32 ip_dst)
+compose_arp(struct dp_packet *b, uint16_t arp_op,
+            const struct eth_addr arp_sha, const struct eth_addr arp_tha,
+            bool broadcast, ovs_be32 arp_spa, ovs_be32 arp_tpa)
 {
     struct eth_header *eth;
     struct arp_eth_header *arp;
@@ -1024,8 +1029,8 @@ compose_arp(struct dp_packet *b, const uint8_t eth_src[ETH_ADDR_LEN],
     dp_packet_reserve(b, 2 + VLAN_HEADER_LEN);
 
     eth = dp_packet_put_uninit(b, sizeof *eth);
-    memcpy(eth->eth_dst, eth_addr_broadcast, ETH_ADDR_LEN);
-    memcpy(eth->eth_src, eth_src, ETH_ADDR_LEN);
+    eth->eth_dst = broadcast ? eth_addr_broadcast : arp_tha;
+    eth->eth_src = arp_sha;
     eth->eth_type = htons(ETH_TYPE_ARP);
 
     arp = dp_packet_put_uninit(b, sizeof *arp);
@@ -1033,14 +1038,14 @@ compose_arp(struct dp_packet *b, const uint8_t eth_src[ETH_ADDR_LEN],
     arp->ar_pro = htons(ARP_PRO_IP);
     arp->ar_hln = sizeof arp->ar_sha;
     arp->ar_pln = sizeof arp->ar_spa;
-    arp->ar_op = htons(ARP_OP_REQUEST);
-    memcpy(arp->ar_sha, eth_src, ETH_ADDR_LEN);
-    memset(arp->ar_tha, 0, ETH_ADDR_LEN);
+    arp->ar_op = htons(arp_op);
+    arp->ar_sha = arp_sha;
+    arp->ar_tha = arp_tha;
 
-    put_16aligned_be32(&arp->ar_spa, ip_src);
-    put_16aligned_be32(&arp->ar_tpa, ip_dst);
+    put_16aligned_be32(&arp->ar_spa, arp_spa);
+    put_16aligned_be32(&arp->ar_tpa, arp_tpa);
 
-    dp_packet_set_frame(b, eth);
+    dp_packet_reset_offsets(b);
     dp_packet_set_l3(b, arp);
 }
 
@@ -1057,3 +1062,4 @@ packet_csum_pseudoheader(const struct ip_header *ip)
 
     return partial;
 }
+