debian: Avoid implying that Linux 2.6.9 is supported.
[openvswitch] / lib / nx-match.c
index 5fc6aa24942f1253b95e1099ef70a14956790589..f66c6556a8f12de051288df332755e3d470010f3 100644 (file)
@@ -18,6 +18,8 @@
 
 #include "nx-match.h"
 
+#include <netinet/icmp6.h>
+
 #include "classifier.h"
 #include "dynamic-string.h"
 #include "ofp-util.h"
@@ -76,16 +78,6 @@ static struct nxm_field nxm_fields[N_NXM_FIELDS] = {
 /* Hash table of 'nxm_fields'. */
 static struct hmap all_nxm_fields = HMAP_INITIALIZER(&all_nxm_fields);
 
-/* Possible masks for NXM_OF_ETH_DST_W. */
-static const uint8_t eth_all_0s[ETH_ADDR_LEN]
-    = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-static const uint8_t eth_all_1s[ETH_ADDR_LEN]
-    = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-static const uint8_t eth_mcast_1[ETH_ADDR_LEN]
-    = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
-static const uint8_t eth_mcast_0[ETH_ADDR_LEN]
-    = {0xfe, 0xff, 0xff, 0xff, 0xff, 0xff};
-
 static void
 nxm_init(void)
 {
@@ -174,9 +166,6 @@ parse_nxm_entry(struct cls_rule *rule, const struct nxm_field *f,
         /* Metadata. */
     case NFI_NXM_OF_IN_PORT:
         flow->in_port = ntohs(get_unaligned_be16(value));
-        if (flow->in_port == OFPP_LOCAL) {
-            flow->in_port = ODPP_LOCAL;
-        }
         return 0;
 
         /* Ethernet header. */
@@ -193,18 +182,8 @@ parse_nxm_entry(struct cls_rule *rule, const struct nxm_field *f,
         if ((wc->wildcards & (FWW_DL_DST | FWW_ETH_MCAST))
             != (FWW_DL_DST | FWW_ETH_MCAST)) {
             return NXM_DUP_TYPE;
-        } else if (eth_addr_equals(mask, eth_mcast_1)) {
-            wc->wildcards &= ~FWW_ETH_MCAST;
-            flow->dl_dst[0] = *(uint8_t *) value & 0x01;
-        } else if (eth_addr_equals(mask, eth_mcast_0)) {
-            wc->wildcards &= ~FWW_DL_DST;
-            memcpy(flow->dl_dst, value, ETH_ADDR_LEN);
-            flow->dl_dst[0] &= 0xfe;
-        } else if (eth_addr_equals(mask, eth_all_0s)) {
-            return 0;
-        } else if (eth_addr_equals(mask, eth_all_1s)) {
-            wc->wildcards &= ~(FWW_DL_DST | FWW_ETH_MCAST);
-            memcpy(flow->dl_dst, value, ETH_ADDR_LEN);
+        } else if (flow_wildcards_is_dl_dst_mask_valid(mask)) {
+            cls_rule_set_dl_dst_masked(rule, value, mask);
             return 0;
         } else {
             return NXM_BAD_MASK;
@@ -363,6 +342,30 @@ parse_nxm_entry(struct cls_rule *rule, const struct nxm_field *f,
         flow->tp_dst = htons(*(uint8_t *) value);
         return 0;
 
+        /* IPv6 Neighbor Discovery. */
+    case NFI_NXM_NX_ND_TARGET:
+        /* We've already verified that it's an ICMPv6 message. */
+        if ((flow->tp_src != htons(ND_NEIGHBOR_SOLICIT)) 
+                    && (flow->tp_src != htons(ND_NEIGHBOR_ADVERT))) {
+            return NXM_BAD_PREREQ;
+        }
+        memcpy(&flow->nd_target, value, sizeof flow->nd_target);
+        return 0;
+    case NFI_NXM_NX_ND_SLL:
+        /* We've already verified that it's an ICMPv6 message. */
+        if (flow->tp_src != htons(ND_NEIGHBOR_SOLICIT)) {
+            return NXM_BAD_PREREQ;
+        }
+        memcpy(flow->arp_sha, value, ETH_ADDR_LEN);
+        return 0;
+    case NFI_NXM_NX_ND_TLL:
+        /* We've already verified that it's an ICMPv6 message. */
+        if (flow->tp_src != htons(ND_NEIGHBOR_ADVERT)) {
+            return NXM_BAD_PREREQ;
+        }
+        memcpy(flow->arp_tha, value, ETH_ADDR_LEN);
+        return 0;
+
         /* ARP header. */
     case NFI_NXM_OF_ARP_OP:
         if (ntohs(get_unaligned_be16(value)) > 255) {
@@ -652,20 +655,15 @@ nxm_put_eth(struct ofpbuf *b, uint32_t header,
 
 static void
 nxm_put_eth_dst(struct ofpbuf *b,
-                uint32_t wc, const uint8_t value[ETH_ADDR_LEN])
+                flow_wildcards_t wc, const uint8_t value[ETH_ADDR_LEN])
 {
     switch (wc & (FWW_DL_DST | FWW_ETH_MCAST)) {
     case FWW_DL_DST | FWW_ETH_MCAST:
         break;
-    case FWW_DL_DST:
-        nxm_put_header(b, NXM_OF_ETH_DST_W);
-        ofpbuf_put(b, value, ETH_ADDR_LEN);
-        ofpbuf_put(b, eth_mcast_1, ETH_ADDR_LEN);
-        break;
-    case FWW_ETH_MCAST:
+    default:
         nxm_put_header(b, NXM_OF_ETH_DST_W);
         ofpbuf_put(b, value, ETH_ADDR_LEN);
-        ofpbuf_put(b, eth_mcast_0, ETH_ADDR_LEN);
+        ofpbuf_put(b, flow_wildcards_to_dl_dst_mask(wc), ETH_ADDR_LEN);
         break;
     case 0:
         nxm_put_eth(b, NXM_OF_ETH_DST, value);
@@ -711,9 +709,6 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
     /* Metadata. */
     if (!(wc & FWW_IN_PORT)) {
         uint16_t in_port = flow->in_port;
-        if (in_port == ODPP_LOCAL) {
-            in_port = OFPP_LOCAL;
-        }
         nxm_put_16(b, NXM_OF_IN_PORT, htons(in_port));
     }
 
@@ -811,6 +806,22 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
             case IPPROTO_ICMPV6:
                 if (!(wc & FWW_TP_SRC)) {
                     nxm_put_8(b, NXM_NX_ICMPV6_TYPE, ntohs(flow->tp_src));
+
+                    if (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT) ||
+                        flow->tp_src == htons(ND_NEIGHBOR_ADVERT)) {
+                        if (!(wc & FWW_ND_TARGET)) {
+                            nxm_put_ipv6(b, NXM_NX_ND_TARGET, &flow->nd_target,
+                                         &in6addr_exact);
+                        }
+                        if (!(wc & FWW_ARP_SHA)
+                            && flow->tp_src == htons(ND_NEIGHBOR_SOLICIT)) {
+                            nxm_put_eth(b, NXM_NX_ND_SLL, flow->arp_sha);
+                        }
+                        if (!(wc & FWW_ARP_THA)
+                            && flow->tp_src == htons(ND_NEIGHBOR_ADVERT)) {
+                            nxm_put_eth(b, NXM_NX_ND_TLL, flow->arp_tha);
+                        }
+                    }
                 }
                 if (!(wc & FWW_TP_DST)) {
                     nxm_put_8(b, NXM_NX_ICMPV6_CODE, ntohs(flow->tp_dst));
@@ -1234,7 +1245,7 @@ nxm_read_field(const struct nxm_field *src, const struct flow *flow)
 {
     switch (src->index) {
     case NFI_NXM_OF_IN_PORT:
-        return flow->in_port == ODPP_LOCAL ? OFPP_LOCAL : flow->in_port;
+        return flow->in_port;
 
     case NFI_NXM_OF_ETH_DST:
         return eth_addr_to_uint64(flow->dl_dst);
@@ -1303,9 +1314,11 @@ nxm_read_field(const struct nxm_field *src, const struct flow *flow)
 #endif
 
     case NFI_NXM_NX_ARP_SHA:
+    case NFI_NXM_NX_ND_SLL:
         return eth_addr_to_uint64(flow->arp_sha);
 
     case NFI_NXM_NX_ARP_THA:
+    case NFI_NXM_NX_ND_TLL:
         return eth_addr_to_uint64(flow->arp_tha);
 
     case NFI_NXM_NX_TUN_ID_W:
@@ -1319,6 +1332,7 @@ nxm_read_field(const struct nxm_field *src, const struct flow *flow)
     case NFI_NXM_NX_IPV6_SRC_W:
     case NFI_NXM_NX_IPV6_DST:
     case NFI_NXM_NX_IPV6_DST_W:
+    case NFI_NXM_NX_ND_TARGET:
     case N_NXM_FIELDS:
         NOT_REACHED();
     }
@@ -1392,6 +1406,9 @@ nxm_write_field(const struct nxm_field *dst, struct flow *flow,
     case NFI_NXM_NX_IPV6_DST_W:
     case NFI_NXM_NX_ICMPV6_TYPE:
     case NFI_NXM_NX_ICMPV6_CODE:
+    case NFI_NXM_NX_ND_TARGET:
+    case NFI_NXM_NX_ND_SLL:
+    case NFI_NXM_NX_ND_TLL:
     case N_NXM_FIELDS:
         NOT_REACHED();
     }