Support matching and modifying IP TTL.
authorJustin Pettit <jpettit@nicira.com>
Sat, 5 Nov 2011 22:48:12 +0000 (15:48 -0700)
committerJustin Pettit <jpettit@nicira.com>
Wed, 9 Nov 2011 21:24:52 +0000 (13:24 -0800)
Add support matching the IPv4 TTL and IPv6 hop limit fields.  This
commit also adds support for modifying the IPv4 TTL.  Modifying the IPv6
hop limit isn't currently supported, since we don't support modifying
IPv6 headers.

We will likely want to change the user-space interface, since basic
matching and setting the TTL are not generally useful.  We will probably
want the ability to match on extraordinary events (such as TTL of 0 or 1)
and a decrement action.

Feature #8024

Signed-off-by: Justin Pettit <jpettit@nicira.com>
Acked-by: Jesse Gross <jesse@nicira.com>
26 files changed:
NEWS
datapath/actions.c
datapath/flow.c
datapath/flow.h
include/linux/openvswitch.h
include/openflow/nicira-ext.h
lib/classifier.c
lib/classifier.h
lib/dpif-netdev.c
lib/flow.c
lib/flow.h
lib/meta-flow.c
lib/meta-flow.h
lib/nx-match.c
lib/nx-match.def
lib/nx-match.h
lib/odp-util.c
lib/odp-util.h
lib/ofp-parse.c
lib/ofp-util.c
ofproto/ofproto-dpif.c
tests/odp.at
tests/ofp-print.at
tests/ofproto-dpif.at
tests/ovs-ofctl.at
utilities/ovs-ofctl.8.in

diff --git a/NEWS b/NEWS
index 6f3b2397cf7821aecd35c9413aa60077f6a86165..30714c500900d0b31c9e8e7a96e2d3952514b11a 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,7 +3,9 @@ post-v1.3.0
     - OpenFlow:
        - Added ability to match on IPv6 flow label through NXM.
        - Added ability to match on ECN bits in IPv4 and IPv6 through NXM.
+       - Added ability to match on TTL in IPv4 and IPv6 through NXM.
        - Added ability to modify ECN bits in IPv4.
+       - Added ability to modify TTL in IPv4.
     - ovs-appctl:
       - New "fdb/flush" command to flush bridge's MAC learning table.
 
index 3296dee8437a7400afd52290d17c24bec8c75cd1..61b903f683fe24d1158dad6ea9acbf6882eeb626 100644 (file)
@@ -151,6 +151,12 @@ static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh,
        *addr = new_addr;
 }
 
+static void set_ip_ttl(struct sk_buff *skb, struct iphdr *nh, u8 new_ttl)
+{
+       csum_replace2(&nh->check, htons(nh->ttl << 8), htons(new_ttl << 8));
+       nh->ttl = new_ttl;
+}
+
 static int set_ipv4(struct sk_buff *skb, const struct ovs_key_ipv4 *ipv4_key)
 {
        struct iphdr *nh;
@@ -172,6 +178,9 @@ static int set_ipv4(struct sk_buff *skb, const struct ovs_key_ipv4 *ipv4_key)
        if (ipv4_key->ipv4_tos != nh->tos)
                ipv4_change_dsfield(nh, 0, ipv4_key->ipv4_tos);
 
+       if (ipv4_key->ipv4_ttl != nh->ttl)
+               set_ip_ttl(skb, nh, ipv4_key->ipv4_ttl);
+
        return 0;
 }
 
index 250b38eef668def5b06bc9d00226c7073d131389..54d7bda370173b2259d430caf9047808113b19e8 100644 (file)
@@ -200,6 +200,7 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key,
 
        key->ip.proto = NEXTHDR_NONE;
        key->ip.tos = ipv6_get_dsfield(nh);
+       key->ip.ttl = nh->hop_limit;
        key->ipv6.label = *(__be32 *)nh & htonl(IPV6_FLOWINFO_FLOWLABEL);
        ipv6_addr_copy(&key->ipv6.addr.src, &nh->saddr);
        ipv6_addr_copy(&key->ipv6.addr.dst, &nh->daddr);
@@ -689,6 +690,7 @@ int flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
 
                key->ip.proto = nh->protocol;
                key->ip.tos = nh->tos;
+               key->ip.ttl = nh->ttl;
 
                offset = nh->frag_off & htons(IP_OFFSET);
                if (offset) {
@@ -961,6 +963,7 @@ int flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
                                goto invalid;
                        swkey->ip.proto = ipv4_key->ipv4_proto;
                        swkey->ip.tos = ipv4_key->ipv4_tos;
+                       swkey->ip.ttl = ipv4_key->ipv4_ttl;
                        swkey->ip.frag = ipv4_key->ipv4_frag;
                        swkey->ipv4.addr.src = ipv4_key->ipv4_src;
                        swkey->ipv4.addr.dst = ipv4_key->ipv4_dst;
@@ -976,6 +979,7 @@ int flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
                        swkey->ipv6.label = ipv6_key->ipv6_label;
                        swkey->ip.proto = ipv6_key->ipv6_proto;
                        swkey->ip.tos = ipv6_key->ipv6_tos;
+                       swkey->ip.ttl = ipv6_key->ipv6_hlimit;
                        swkey->ip.frag = ipv6_key->ipv6_frag;
                        memcpy(&swkey->ipv6.addr.src, ipv6_key->ipv6_src,
                                        sizeof(swkey->ipv6.addr.src));
@@ -1240,11 +1244,11 @@ int flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb)
                if (!nla)
                        goto nla_put_failure;
                ipv4_key = nla_data(nla);
-               memset(ipv4_key, 0, sizeof(struct ovs_key_ipv4));
                ipv4_key->ipv4_src = swkey->ipv4.addr.src;
                ipv4_key->ipv4_dst = swkey->ipv4.addr.dst;
                ipv4_key->ipv4_proto = swkey->ip.proto;
                ipv4_key->ipv4_tos = swkey->ip.tos;
+               ipv4_key->ipv4_ttl = swkey->ip.ttl;
                ipv4_key->ipv4_frag = swkey->ip.frag;
        } else if (swkey->eth.type == htons(ETH_P_IPV6)) {
                struct ovs_key_ipv6 *ipv6_key;
@@ -1253,7 +1257,6 @@ int flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb)
                if (!nla)
                        goto nla_put_failure;
                ipv6_key = nla_data(nla);
-               memset(ipv6_key, 0, sizeof(struct ovs_key_ipv6));
                memcpy(ipv6_key->ipv6_src, &swkey->ipv6.addr.src,
                                sizeof(ipv6_key->ipv6_src));
                memcpy(ipv6_key->ipv6_dst, &swkey->ipv6.addr.dst,
@@ -1261,6 +1264,7 @@ int flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb)
                ipv6_key->ipv6_label = swkey->ipv6.label;
                ipv6_key->ipv6_proto = swkey->ip.proto;
                ipv6_key->ipv6_tos = swkey->ip.tos;
+               ipv6_key->ipv6_hlimit = swkey->ip.ttl;
                ipv6_key->ipv6_frag = swkey->ip.frag;
        } else if (swkey->eth.type == htons(ETH_P_ARP)) {
                struct ovs_key_arp *arp_key;
index b08111fbb7f30ad0d225785aa7be2e03ce2c2aac..c08d3dfeb80bb0bf91a0b40ca020d270cae25832 100644 (file)
@@ -45,6 +45,7 @@ struct sw_flow_key {
        struct {
                u8     proto;           /* IP protocol or lower 8 bits of ARP opcode. */
                u8     tos;             /* IP ToS. */
+               u8     ttl;         /* IP TTL/hop limit. */
                u8     frag;        /* One of OVS_FRAG_TYPE_*. */
        } ip;
        union {
@@ -143,7 +144,7 @@ u64 flow_used_time(unsigned long flow_jiffies);
  *  OVS_KEY_ATTR_ETHERNET     12    --     4     16
  *  OVS_KEY_ATTR_8021Q         4    --     4      8
  *  OVS_KEY_ATTR_ETHERTYPE     2     2     4      8
- *  OVS_KEY_ATTR_IPV6         39     1     4     44
+ *  OVS_KEY_ATTR_IPV6         40    --     4     44
  *  OVS_KEY_ATTR_ICMPV6        2     2     4      8
  *  OVS_KEY_ATTR_ND           28    --     4     32
  *  -------------------------------------------------
index 62668a62f081042405b9e9cc917cc84b2c6dc8e8..c94c5347e0c3c493633e9e9490240d724dd65035 100644 (file)
@@ -316,6 +316,7 @@ struct ovs_key_ipv4 {
        __be32 ipv4_dst;
        __u8   ipv4_proto;
        __u8   ipv4_tos;
+       __u8   ipv4_ttl;
        __u8   ipv4_frag;       /* One of OVS_FRAG_TYPE_*. */
 };
 
@@ -325,6 +326,7 @@ struct ovs_key_ipv6 {
        __be32 ipv6_label;      /* 20-bits in least-significant bits. */
        __u8   ipv6_proto;
        __u8   ipv6_tos;
+       __u8   ipv6_hlimit;
        __u8   ipv6_frag;       /* One of OVS_FRAG_TYPE_*. */
 };
 
index b55ea9d0c73b6c446cea4d193a4c560e879b0777..06b9035ab6bb8f9820b83b8b695c2eb7f0aeebf6 100644 (file)
@@ -1632,6 +1632,15 @@ OFP_ASSERT(sizeof(struct nx_action_output_reg) == 24);
  * Masking: Not maskable. */
 #define NXM_NX_IP_ECN      NXM_HEADER  (0x0001, 28, 1)
 
+/* The time-to-live/hop limit of the IP header.
+ *
+ * Prereqs: NXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd.
+ *
+ * Format: 8-bit integer.
+ *
+ * Masking: Not maskable. */
+#define NXM_NX_IP_TTL      NXM_HEADER  (0x0001, 29, 1)
+
 /* ## --------------------- ## */
 /* ## Requests and replies. ## */
 /* ## --------------------- ## */
index 39a84d5259da42fe9abf1cdc9f1f41a201a519f9..842166cd438061ee3465ab683b1261a37498d250 100644 (file)
@@ -333,6 +333,13 @@ cls_rule_set_nw_ecn(struct cls_rule *rule, uint8_t nw_ecn)
     rule->flow.tos |= nw_ecn & IP_ECN_MASK;
 }
 
+void
+cls_rule_set_nw_ttl(struct cls_rule *rule, uint8_t nw_ttl)
+{
+    rule->wc.wildcards &= ~FWW_NW_TTL;
+    rule->flow.nw_ttl = nw_ttl;
+}
+
 void
 cls_rule_set_frag(struct cls_rule *rule, uint8_t frag)
 {
@@ -480,7 +487,7 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
 
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 5);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 6);
 
     if (rule->priority != OFP_DEFAULT_PRIORITY) {
         ds_put_format(s, "priority=%d,", rule->priority);
@@ -631,6 +638,9 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
     if (wc->tos_mask & IP_ECN_MASK) {
         ds_put_format(s, "nw_ecn=%"PRIu8",", f->tos & IP_ECN_MASK);
     }
+    if (!(w & FWW_NW_TTL)) {
+        ds_put_format(s, "nw_ttl=%"PRIu8",", f->nw_ttl);
+    }
     switch (wc->frag_mask) {
     case FLOW_FRAG_ANY | FLOW_FRAG_LATER:
         ds_put_format(s, "frag=%s,",
@@ -1177,7 +1187,7 @@ flow_equal_except(const struct flow *a, const struct flow *b,
     const flow_wildcards_t wc = wildcards->wildcards;
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 5);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 6);
 
     for (i = 0; i < FLOW_N_REGS; i++) {
         if ((a->regs[i] ^ b->regs[i]) & wildcards->reg_masks[i]) {
@@ -1204,6 +1214,7 @@ flow_equal_except(const struct flow *a, const struct flow *b,
             && (wc & FWW_ETH_MCAST
                 || !((a->dl_dst[0] ^ b->dl_dst[0]) & 0x01))
             && (wc & FWW_NW_PROTO || a->nw_proto == b->nw_proto)
+            && (wc & FWW_NW_TTL || a->nw_ttl == b->nw_ttl)
             && !((a->tos ^ b->tos) & wildcards->tos_mask)
             && !((a->frag ^ b->frag) & wildcards->frag_mask)
             && (wc & FWW_ARP_SHA || eth_addr_equals(a->arp_sha, b->arp_sha))
index 581ee832ea092c32e67dac3dd3e14814a6404056..d6ab74e8a89bdd76c483237bbe448f1c5427eefd 100644 (file)
@@ -118,6 +118,7 @@ void cls_rule_set_nw_dst(struct cls_rule *, ovs_be32);
 bool cls_rule_set_nw_dst_masked(struct cls_rule *, ovs_be32 ip, ovs_be32 mask);
 void cls_rule_set_nw_dscp(struct cls_rule *, uint8_t);
 void cls_rule_set_nw_ecn(struct cls_rule *, uint8_t);
+void cls_rule_set_nw_ttl(struct cls_rule *, uint8_t);
 void cls_rule_set_frag(struct cls_rule *, uint8_t frag);
 void cls_rule_set_frag_masked(struct cls_rule *, uint8_t frag, uint8_t mask);
 void cls_rule_set_icmp_type(struct cls_rule *, uint8_t);
index d7768990d7cc0dc343f1019ea82123a972caec9c..27125d3161ffeb3c1c08d32403df01e192c7fe1a 100644 (file)
@@ -1091,6 +1091,16 @@ dp_netdev_set_ip_tos(struct ip_header *nh, uint8_t new_tos)
     *field = new_tos;
 }
 
+static void
+dp_netdev_set_ip_ttl(struct ip_header *nh, uint8_t new_ttl)
+{
+    uint8_t *field = &nh->ip_ttl;
+
+    nh->ip_csum = recalc_csum16(nh->ip_csum, htons(*field << 8),
+                                   htons(new_ttl << 8));
+    *field = new_ttl;
+}
+
 static void
 dp_netdev_set_ipv4(struct ofpbuf *packet, const struct ovs_key_ipv4 *ipv4_key)
 {
@@ -1105,6 +1115,9 @@ dp_netdev_set_ipv4(struct ofpbuf *packet, const struct ovs_key_ipv4 *ipv4_key)
     if (nh->ip_tos != ipv4_key->ipv4_tos) {
         dp_netdev_set_ip_tos(nh, ipv4_key->ipv4_tos);
     }
+    if (nh->ip_ttl != ipv4_key->ipv4_ttl) {
+        dp_netdev_set_ip_ttl(nh, ipv4_key->ipv4_ttl);
+    }
 }
 
 static void
index bbef34a611340afdaa9e0d2da81fbc1bf9763f46..e1ce19b91776a0d095e85226572f72254f7d150f 100644 (file)
@@ -150,6 +150,7 @@ parse_ipv6(struct ofpbuf *packet, struct flow *flow)
     tc_flow = get_unaligned_be32(&nh->ip6_flow);
     flow->tos = ntohl(tc_flow) >> 4;
     flow->ipv6_label = tc_flow & htonl(IPV6_LABEL_MASK);
+    flow->nw_ttl = nh->ip6_hlim;
     flow->nw_proto = IPPROTO_NONE;
 
     while (1) {
@@ -376,6 +377,7 @@ flow_extract(struct ofpbuf *packet, uint32_t priority, ovs_be64 tun_id,
                     flow->frag |= FLOW_FRAG_LATER;
                 }
             }
+            flow->nw_ttl = nh->ip_ttl;
 
             if (!(nh->ip_frag_off & htons(IP_FRAG_OFF_MASK))) {
                 if (flow->nw_proto == IPPROTO_TCP) {
@@ -437,7 +439,7 @@ flow_zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
     const flow_wildcards_t wc = wildcards->wildcards;
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 5);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 6);
 
     for (i = 0; i < FLOW_N_REGS; i++) {
         flow->regs[i] &= wildcards->reg_masks[i];
@@ -475,6 +477,9 @@ flow_zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
         flow->ipv6_label = htonl(0);
     }
     flow->tos &= wildcards->tos_mask;
+    if (wc & FWW_NW_TTL) {
+        flow->nw_ttl = 0;
+    }
     flow->frag &= wildcards->frag_mask;
     if (wc & FWW_ARP_SHA) {
         memset(flow->arp_sha, 0, sizeof flow->arp_sha);
@@ -525,17 +530,19 @@ flow_format(struct ds *ds, const struct flow *flow)
                   ntohs(flow->dl_type));
 
     if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
-        ds_put_format(ds, " label%#"PRIx32" proto%"PRIu8" tos%#"PRIx8" ipv6",
-                      ntohl(flow->ipv6_label), flow->nw_proto, flow->tos);
+        ds_put_format(ds, " label%#"PRIx32" proto%"PRIu8" tos%#"PRIx8
+                          " ttl%"PRIu8" ipv6",
+                      ntohl(flow->ipv6_label), flow->nw_proto,
+                      flow->tos, flow->nw_ttl);
         print_ipv6_addr(ds, &flow->ipv6_src);
         ds_put_cstr(ds, "->");
         print_ipv6_addr(ds, &flow->ipv6_dst);
 
     } else {
-        ds_put_format(ds, " proto%"PRIu8" tos%#"PRIx8" ip"IP_FMT"->"IP_FMT,
-                      flow->nw_proto, flow->tos,
-                      IP_ARGS(&flow->nw_src),
-                      IP_ARGS(&flow->nw_dst));
+        ds_put_format(ds, " proto%"PRIu8" tos%#"PRIx8" ttl%"PRIu8
+                          " ip"IP_FMT"->"IP_FMT,
+                      flow->nw_proto, flow->tos, flow->nw_ttl,
+                      IP_ARGS(&flow->nw_src), IP_ARGS(&flow->nw_dst));
     }
     if (flow->frag) {
         ds_put_format(ds, " frag(%s)",
@@ -568,7 +575,7 @@ flow_print(FILE *stream, const struct flow *flow)
 void
 flow_wildcards_init_catchall(struct flow_wildcards *wc)
 {
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 5);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 6);
 
     wc->wildcards = FWW_ALL;
     wc->tun_id_mask = htonll(0);
@@ -588,7 +595,7 @@ flow_wildcards_init_catchall(struct flow_wildcards *wc)
 void
 flow_wildcards_init_exact(struct flow_wildcards *wc)
 {
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 5);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 6);
 
     wc->wildcards = 0;
     wc->tun_id_mask = htonll(UINT64_MAX);
@@ -610,7 +617,7 @@ flow_wildcards_is_exact(const struct flow_wildcards *wc)
 {
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 5);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 6);
 
     if (wc->wildcards
         || wc->tun_id_mask != htonll(UINT64_MAX)
@@ -640,7 +647,7 @@ flow_wildcards_is_catchall(const struct flow_wildcards *wc)
 {
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 5);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 6);
 
     if (wc->wildcards != FWW_ALL
         || wc->tun_id_mask != htonll(0)
index af634fb966054f75f00611ba41707e28eaa4f448..e02cff677fd034c2598e8efe3d24125c31566d61 100644 (file)
@@ -35,7 +35,7 @@ struct ofpbuf;
 /* This sequence number should be incremented whenever anything involving flows
  * or the wildcarding of flows changes.  This will cause build assertion
  * failures in places which likely need to be updated. */
-#define FLOW_WC_SEQ 5
+#define FLOW_WC_SEQ 6
 
 #define FLOW_N_REGS 5
 BUILD_ASSERT_DECL(FLOW_N_REGS <= NXM_NX_MAX_REGS);
@@ -73,20 +73,21 @@ struct flow {
     uint8_t tos;                /* IP ToS. */
     uint8_t arp_sha[6];         /* ARP/ND source hardware address. */
     uint8_t arp_tha[6];         /* ARP/ND target hardware address. */
+    uint8_t nw_ttl;             /* IP TTL/Hop Limit. */
     uint8_t frag;               /* FLOW_FRAG_* flags. */
-    uint8_t reserved[7];        /* Reserved for 64-bit packing. */
+    uint8_t reserved[6];        /* Reserved for 64-bit packing. */
 };
 
 /* Assert that there are FLOW_SIG_SIZE bytes of significant data in "struct
  * flow", followed by FLOW_PAD_SIZE bytes of padding. */
-#define FLOW_SIG_SIZE (109 + FLOW_N_REGS * 4)
-#define FLOW_PAD_SIZE 7
+#define FLOW_SIG_SIZE (110 + FLOW_N_REGS * 4)
+#define FLOW_PAD_SIZE 6
 BUILD_ASSERT_DECL(offsetof(struct flow, frag) == FLOW_SIG_SIZE - 1);
 BUILD_ASSERT_DECL(sizeof(((struct flow *)0)->frag) == 1);
 BUILD_ASSERT_DECL(sizeof(struct flow) == FLOW_SIG_SIZE + FLOW_PAD_SIZE);
 
 /* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
-BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 129 && FLOW_WC_SEQ == 5);
+BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 130 && FLOW_WC_SEQ == 6);
 
 void flow_extract(struct ofpbuf *, uint32_t priority, ovs_be64 tun_id,
                   uint16_t in_port, struct flow *);
@@ -143,10 +144,11 @@ typedef unsigned int OVS_BITWISE flow_wildcards_t;
 #define FWW_ARP_THA     ((OVS_FORCE flow_wildcards_t) (1 << 9))
 #define FWW_ND_TARGET   ((OVS_FORCE flow_wildcards_t) (1 << 10))
 #define FWW_IPV6_LABEL  ((OVS_FORCE flow_wildcards_t) (1 << 11))
-#define FWW_ALL         ((OVS_FORCE flow_wildcards_t) (((1 << 12)) - 1))
+#define FWW_NW_TTL      ((OVS_FORCE flow_wildcards_t) (1 << 12))
+#define FWW_ALL         ((OVS_FORCE flow_wildcards_t) (((1 << 13)) - 1))
 
 /* Remember to update FLOW_WC_SEQ when adding or removing FWW_*. */
-BUILD_ASSERT_DECL(FWW_ALL == ((1 << 12) - 1) && FLOW_WC_SEQ == 5);
+BUILD_ASSERT_DECL(FWW_ALL == ((1 << 13) - 1) && FLOW_WC_SEQ == 6);
 
 /* Information on wildcards for a flow, as a supplement to "struct flow".
  *
@@ -167,7 +169,7 @@ struct flow_wildcards {
 };
 
 /* Remember to update FLOW_WC_SEQ when updating struct flow_wildcards. */
-BUILD_ASSERT_DECL(sizeof(struct flow_wildcards) == 80 && FLOW_WC_SEQ == 5);
+BUILD_ASSERT_DECL(sizeof(struct flow_wildcards) == 80 && FLOW_WC_SEQ == 6);
 
 void flow_wildcards_init_catchall(struct flow_wildcards *);
 void flow_wildcards_init_exact(struct flow_wildcards *);
index d8153873f03ba50f64685d73873ecedab8fd6f4e..2df1cb48557c66cfffcd91a47600db00b488e4c3 100644 (file)
@@ -201,6 +201,13 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         MFS_DECIMAL,
         MFP_IP_ANY,
         NXM_NX_IP_ECN,
+    }, {
+        MFF_IP_TTL, "nw_ttl", NULL,
+        MF_FIELD_SIZES(u8),
+        MFM_NONE, FWW_NW_TTL,
+        MFS_DECIMAL,
+        MFP_IP_ANY,
+        NXM_NX_IP_TTL,
     }, {
         MFF_IP_FRAG, "ip_frag", NULL,
         1, 2,
@@ -369,6 +376,7 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
     case MFF_ETH_SRC:
     case MFF_ETH_TYPE:
     case MFF_IP_PROTO:
+    case MFF_IP_TTL:
     case MFF_IPV6_LABEL:
     case MFF_ARP_OP:
     case MFF_ARP_SHA:
@@ -462,6 +470,7 @@ mf_get_mask(const struct mf_field *mf, const struct flow_wildcards *wc,
     case MFF_ETH_SRC:
     case MFF_ETH_TYPE:
     case MFF_IP_PROTO:
+    case MFF_IP_TTL:
     case MFF_IPV6_LABEL:
     case MFF_ARP_OP:
     case MFF_ARP_SHA:
@@ -689,6 +698,7 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
     case MFF_IPV6_SRC:
     case MFF_IPV6_DST:
     case MFF_IP_PROTO:
+    case MFF_IP_TTL:
     case MFF_ARP_SPA:
     case MFF_ARP_TPA:
     case MFF_ARP_SHA:
@@ -821,6 +831,10 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
         value->u8 = flow->tos & IP_ECN_MASK;
         break;
 
+    case MFF_IP_TTL:
+        value->u8 = flow->nw_ttl;
+        break;
+
     case MFF_IP_FRAG:
         value->u8 = flow->frag;
         break;
@@ -976,6 +990,10 @@ mf_set_value(const struct mf_field *mf,
         cls_rule_set_nw_ecn(rule, value->u8);
         break;
 
+    case MFF_IP_TTL:
+        cls_rule_set_nw_ttl(rule, value->u8);
+        break;
+
     case MFF_IP_FRAG:
         cls_rule_set_frag(rule, value->u8);
         break;
@@ -1149,6 +1167,11 @@ mf_set_wild(const struct mf_field *mf, struct cls_rule *rule)
         rule->flow.tos &= ~IP_ECN_MASK;
         break;
 
+    case MFF_IP_TTL:
+        rule->wc.wildcards |= FWW_NW_TTL;
+        rule->flow.nw_ttl = 0;
+        break;
+
     case MFF_IP_FRAG:
         rule->wc.frag_mask |= FLOW_FRAG_MASK;
         rule->flow.frag &= ~FLOW_FRAG_MASK;
@@ -1228,6 +1251,7 @@ mf_set(const struct mf_field *mf,
     case MFF_VLAN_PCP:
     case MFF_IPV6_LABEL:
     case MFF_IP_PROTO:
+    case MFF_IP_TTL:
     case MFF_IP_DSCP:
     case MFF_IP_ECN:
     case MFF_ARP_OP:
@@ -1433,6 +1457,7 @@ mf_random_value(const struct mf_field *mf, union mf_value *value)
     case MFF_IPV6_SRC:
     case MFF_IPV6_DST:
     case MFF_IP_PROTO:
+    case MFF_IP_TTL:
     case MFF_ARP_SPA:
     case MFF_ARP_TPA:
     case MFF_ARP_SHA:
index eddc549570457d07758381375395056b8605f498..e2079359fb920fe20969883f181ad2a49b9f142c 100644 (file)
@@ -72,6 +72,7 @@ enum mf_field_id {
     MFF_IP_PROTO,               /* u8 (used for IPv4 or IPv6) */
     MFF_IP_DSCP,                /* u8 (used for IPv4 or IPv6) */
     MFF_IP_ECN,                 /* u8 (used for IPv4 or IPv6) */
+    MFF_IP_TTL,                 /* u8 (used for IPv4 or IPv6) */
     MFF_IP_FRAG,                /* u8 (used for IPv4 or IPv6) */
 
     MFF_ARP_OP,                 /* be16 */
index cb73084dfee537fa5bcd9ab30565b0e4f9dc4be0..9919e1f104054a8591cd077075ab98ebb9366e60 100644 (file)
@@ -460,7 +460,7 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
     int match_len;
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 5);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 6);
 
     /* Metadata. */
     if (!(wc & FWW_IN_PORT)) {
@@ -496,6 +496,10 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
             nxm_put_8(b, NXM_NX_IP_ECN, flow->tos & IP_ECN_MASK);
         }
 
+        if (!(wc & FWW_NW_TTL)) {
+            nxm_put_8(b, NXM_NX_IP_TTL, flow->nw_ttl);
+        }
+
         if (!(wc & FWW_NW_PROTO)) {
             nxm_put_8(b, NXM_OF_IP_PROTO, flow->nw_proto);
             switch (flow->nw_proto) {
@@ -550,6 +554,10 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
             nxm_put_8(b, NXM_NX_IP_ECN, flow->tos & IP_ECN_MASK);
         }
 
+        if (!(wc & FWW_NW_TTL)) {
+            nxm_put_8(b, NXM_NX_IP_TTL, flow->nw_ttl);
+        }
+
         if (!(wc & FWW_NW_PROTO)) {
             nxm_put_8(b, NXM_OF_IP_PROTO, flow->nw_proto);
             switch (flow->nw_proto) {
@@ -1058,6 +1066,9 @@ nxm_read_field(const struct nxm_field *src, const struct flow *flow)
     case NFI_NXM_NX_IP_ECN:
         return flow->tos & IP_ECN_MASK;
 
+    case NFI_NXM_NX_IP_TTL:
+        return flow->nw_ttl;
+
     case NFI_NXM_NX_IP_FRAG:
         return flow->frag;
 
@@ -1218,6 +1229,10 @@ nxm_write_field(const struct nxm_field *dst, struct flow *flow,
         flow->tos |= new_value & IP_ECN_MASK;
         break;
 
+    case NFI_NXM_NX_IP_TTL:
+        flow->nw_ttl = new_value;
+        break;
+
     case NFI_NXM_NX_IP_FRAG:
         flow->frag = new_value;
         break;
index 3691043df6e04b74f5f1e0f30acca5ed32074e9a..ea032fc8e54100eae39bb51d8f9d0bf0d9212d1f 100644 (file)
@@ -46,6 +46,7 @@ DEFINE_FIELD_M(NX_IPV6_SRC,   MFF_IPV6_SRC,  false)
 DEFINE_FIELD_M(NX_IPV6_DST,   MFF_IPV6_DST,  false)
 DEFINE_FIELD  (NX_IPV6_LABEL, MFF_IPV6_LABEL,false)
 DEFINE_FIELD  (NX_IP_ECN,     MFF_IP_ECN,     true)
+DEFINE_FIELD  (NX_IP_TTL,     MFF_IP_TTL,     true)
 /* XXX should we have MFF_ICMPV4_TYPE and MFF_ICMPV6_TYPE? */
 DEFINE_FIELD  (NX_ICMPV6_TYPE,MFF_ICMP_TYPE, false)
 DEFINE_FIELD  (NX_ICMPV6_CODE,MFF_ICMP_CODE, false)
index 6a33dbe42c5c3b852c35f39b9549448eab1afc09..0b9a437d143b19e5378854f8e828c973e0e00ad1 100644 (file)
@@ -103,6 +103,7 @@ nxm_decode_n_bits(ovs_be16 ofs_nbits)
  *  NXM_OF_VLAN_TCI     4       2     2      8
  *  NXM_OF_IP_TOS       4       1    --      5
  *  NXM_NX_IP_ECN       4       1    --      5
+ *  NXM_OF_IP_TTL       4       1    --      5
  *  NXM_NX_IP_FRAG      4       1     1      8
  *  NXM_OF_IP_PROTO     4       2    --      6
  *  NXM_OF_IPV6_SRC_W   4      16    16     36
@@ -119,7 +120,7 @@ nxm_decode_n_bits(ovs_be16 ofs_nbits)
  *  NXM_NX_REG_W(4)     4       4     4     12
  *  NXM_NX_TUN_ID_W     4       8     8     20
  *  -------------------------------------------
- *  total                                  270
+ *  total                                  275
  *
  * So this value is conservative.
  */
index aa4931d41fca3b87a474310a0726ddaa3947a013..c4046d71d0955e330bae3c278ae369dc3bff0136 100644 (file)
@@ -369,11 +369,12 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds)
 
     case OVS_KEY_ATTR_IPV4:
         ipv4_key = nl_attr_get(a);
-        ds_put_format(ds, "ipv4(src="IP_FMT",dst="IP_FMT","
-                      "proto=%"PRId8",tos=%#"PRIx8",frag=%s)",
+        ds_put_format(ds, "ipv4(src="IP_FMT",dst="IP_FMT",proto=%"PRId8
+                      ",tos=%#"PRIx8",ttl=%"PRIu8",frag=%s)",
                       IP_ARGS(&ipv4_key->ipv4_src),
                       IP_ARGS(&ipv4_key->ipv4_dst),
                       ipv4_key->ipv4_proto, ipv4_key->ipv4_tos,
+                      ipv4_key->ipv4_ttl,
                       ovs_frag_type_to_string(ipv4_key->ipv4_frag));
         break;
 
@@ -386,9 +387,10 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds)
         inet_ntop(AF_INET6, ipv6_key->ipv6_dst, dst_str, sizeof dst_str);
 
         ds_put_format(ds, "ipv6(src=%s,dst=%s,label=%#"PRIx32",proto=%"PRId8
-                      ",tos=%#"PRIx8",frag=%s)",
+                      ",tos=%#"PRIx8",hlimit=%"PRIu8",frag=%s)",
                       src_str, dst_str, ntohl(ipv6_key->ipv6_label),
                       ipv6_key->ipv6_proto, ipv6_key->ipv6_tos,
+                      ipv6_key->ipv6_hlimit,
                       ovs_frag_type_to_string(ipv6_key->ipv6_frag));
         break;
     }
@@ -606,23 +608,24 @@ parse_odp_key_attr(const char *s, struct ofpbuf *key)
         ovs_be32 ipv4_dst;
         int ipv4_proto;
         int ipv4_tos;
+        int ipv4_ttl;
         char frag[8];
         enum ovs_frag_type ipv4_frag;
         int n = -1;
 
         if (sscanf(s, "ipv4(src="IP_SCAN_FMT",dst="IP_SCAN_FMT","
-                   "proto=%i,tos=%i,frag=%7[a-z])%n",
+                   "proto=%i,tos=%i,ttl=%i,frag=%7[a-z])%n",
                    IP_SCAN_ARGS(&ipv4_src), IP_SCAN_ARGS(&ipv4_dst),
-                   &ipv4_proto, &ipv4_tos, frag, &n) > 0
+                   &ipv4_proto, &ipv4_tos, &ipv4_ttl, frag, &n) > 0
             && n > 0
             && ovs_frag_type_from_string(frag, &ipv4_frag)) {
             struct ovs_key_ipv4 ipv4_key;
 
-            memset(&ipv4_key, 0, sizeof ipv4_key);
             ipv4_key.ipv4_src = ipv4_src;
             ipv4_key.ipv4_dst = ipv4_dst;
             ipv4_key.ipv4_proto = ipv4_proto;
             ipv4_key.ipv4_tos = ipv4_tos;
+            ipv4_key.ipv4_ttl = ipv4_ttl;
             ipv4_key.ipv4_frag = ipv4_frag;
             nl_msg_put_unspec(key, OVS_KEY_ATTR_IPV4,
                               &ipv4_key, sizeof ipv4_key);
@@ -636,19 +639,19 @@ parse_odp_key_attr(const char *s, struct ofpbuf *key)
         int ipv6_label;
         int ipv6_proto;
         int ipv6_tos;
+        int ipv6_hlimit;
         char frag[8];
         enum ovs_frag_type ipv6_frag;
         int n = -1;
 
         if (sscanf(s, "ipv6(src="IPV6_SCAN_FMT",dst="IPV6_SCAN_FMT","
-                   "label=%i,proto=%i,tos=%i,frag=%7[a-z])%n",
+                   "label=%i,proto=%i,tos=%i,hlimit=%i,frag=%7[a-z])%n",
                    ipv6_src_s, ipv6_dst_s, &ipv6_label,
-                   &ipv6_proto, &ipv6_tos, frag, &n) > 0
+                   &ipv6_proto, &ipv6_tos, &ipv6_hlimit, frag, &n) > 0
             && n > 0
             && ovs_frag_type_from_string(frag, &ipv6_frag)) {
             struct ovs_key_ipv6 ipv6_key;
 
-            memset(&ipv6_key, 0, sizeof ipv6_key);
             if (inet_pton(AF_INET6, ipv6_src_s, &ipv6_key.ipv6_src) != 1 ||
                 inet_pton(AF_INET6, ipv6_dst_s, &ipv6_key.ipv6_dst) != 1) {
                 return -EINVAL;
@@ -656,6 +659,7 @@ parse_odp_key_attr(const char *s, struct ofpbuf *key)
             ipv6_key.ipv6_label = htonl(ipv6_label);
             ipv6_key.ipv6_proto = ipv6_proto;
             ipv6_key.ipv6_tos = ipv6_tos;
+            ipv6_key.ipv6_hlimit = ipv6_hlimit;
             ipv6_key.ipv6_frag = ipv6_frag;
             nl_msg_put_unspec(key, OVS_KEY_ATTR_IPV6,
                               &ipv6_key, sizeof ipv6_key);
@@ -872,23 +876,23 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow)
 
         ipv4_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_IPV4,
                                             sizeof *ipv4_key);
-        memset(ipv4_key, 0, sizeof *ipv4_key);
         ipv4_key->ipv4_src = flow->nw_src;
         ipv4_key->ipv4_dst = flow->nw_dst;
         ipv4_key->ipv4_proto = flow->nw_proto;
         ipv4_key->ipv4_tos = flow->tos;
+        ipv4_key->ipv4_ttl = flow->nw_ttl;
         ipv4_key->ipv4_frag = ovs_to_odp_frag(flow->frag);
     } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
         struct ovs_key_ipv6 *ipv6_key;
 
         ipv6_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_IPV6,
                                             sizeof *ipv6_key);
-        memset(ipv6_key, 0, sizeof *ipv6_key);
         memcpy(ipv6_key->ipv6_src, &flow->ipv6_src, sizeof ipv6_key->ipv6_src);
         memcpy(ipv6_key->ipv6_dst, &flow->ipv6_dst, sizeof ipv6_key->ipv6_dst);
         ipv6_key->ipv6_label = flow->ipv6_label;
         ipv6_key->ipv6_proto = flow->nw_proto;
         ipv6_key->ipv6_tos = flow->tos;
+        ipv6_key->ipv6_hlimit = flow->nw_ttl;
         ipv6_key->ipv6_frag = ovs_to_odp_frag(flow->frag);
     } else if (flow->dl_type == htons(ETH_TYPE_ARP)) {
         struct ovs_key_arp *arp_key;
@@ -1061,6 +1065,7 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t key_len,
             flow->nw_dst = ipv4_key->ipv4_dst;
             flow->nw_proto = ipv4_key->ipv4_proto;
             flow->tos = ipv4_key->ipv4_tos;
+            flow->nw_ttl = ipv4_key->ipv4_ttl;
             if (!odp_to_ovs_frag(ipv4_key->ipv4_frag, flow)) {
                 return EINVAL;
             }
@@ -1076,6 +1081,7 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t key_len,
             flow->ipv6_label = ipv6_key->ipv6_label;
             flow->nw_proto = ipv6_key->ipv6_proto;
             flow->tos = ipv6_key->ipv6_tos;
+            flow->nw_ttl = ipv6_key->ipv6_hlimit;
             if (!odp_to_ovs_frag(ipv6_key->ipv6_frag, flow)) {
                 return EINVAL;
             }
index 73c3362ab0d71906e5e5c60dc6f6e33e1e30f378..0f4f9e6b7130ee5b4dd3556258dd1b9dfe4e19cf 100644 (file)
@@ -72,7 +72,7 @@ void format_odp_actions(struct ds *, const struct nlattr *odp_actions,
  *  OVS_KEY_ATTR_ETHERNET     12    --     4     16
  *  OVS_KEY_ATTR_8021Q         4    --     4      8
  *  OVS_KEY_ATTR_ETHERTYPE     2     2     4      8
- *  OVS_KEY_ATTR_IPV6         39     1     4     44
+ *  OVS_KEY_ATTR_IPV6         40    --     4     44
  *  OVS_KEY_ATTR_ICMPV6        2     2     4      8
  *  OVS_KEY_ATTR_ND           28    --     4     32
  *  -------------------------------------------------
index 0146a333caacedc3bb9407bb193361287ef04778..40215511dad0729fc2a5d2070e60e0c616d71a37 100644 (file)
@@ -360,6 +360,7 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
     case OFPUTIL_NXAST_LEARN:
         learn_parse(b, arg, flow);
         break;
+
     case OFPUTIL_NXAST_EXIT:
         ofputil_put_NXAST_EXIT(b);
         break;
index 1b162799ea0eda1f8dac25993add38309c5de9ee..fac21af7edce916f74f0567e0615dd7e5b583ddc 100644 (file)
@@ -101,15 +101,15 @@ static const flow_wildcards_t WC_INVARIANTS = 0
 void
 ofputil_wildcard_from_openflow(uint32_t ofpfw, struct flow_wildcards *wc)
 {
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 5);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 6);
 
     /* Initialize most of rule->wc. */
     flow_wildcards_init_catchall(wc);
     wc->wildcards = (OVS_FORCE flow_wildcards_t) ofpfw & WC_INVARIANTS;
 
     /* Wildcard fields that aren't defined by ofp_match or tun_id. */
-    wc->wildcards |= (FWW_ARP_SHA | FWW_ARP_THA | FWW_ND_TARGET
-                      | FWW_IPV6_LABEL);
+    wc->wildcards |= (FWW_ARP_SHA | FWW_ARP_THA | FWW_NW_TTL
+                      | FWW_ND_TARGET | FWW_IPV6_LABEL);
 
     if (!(ofpfw & OFPFW_NW_TOS)) {
         wc->tos_mask |= IP_DSCP_MASK;
@@ -859,7 +859,7 @@ ofputil_min_flow_format(const struct cls_rule *rule)
 {
     const struct flow_wildcards *wc = &rule->wc;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 5);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 6);
 
     /* Only NXM supports separately wildcards the Ethernet multicast bit. */
     if (!(wc->wildcards & FWW_DL_DST) != !(wc->wildcards & FWW_ETH_MCAST)) {
@@ -902,6 +902,11 @@ ofputil_min_flow_format(const struct cls_rule *rule)
         return NXFF_NXM;
     }
 
+    /* Only NXM supports matching IP TTL/hop limit. */
+    if (!(wc->wildcards & FWW_NW_TTL)) {
+        return NXFF_NXM;
+    }
+
     /* Other formats can express this rule. */
     return NXFF_OPENFLOW10;
 }
@@ -2516,7 +2521,7 @@ ofputil_normalize_rule(struct cls_rule *rule, enum nx_flow_format flow_format)
         MAY_NW_ADDR     = 1 << 0, /* nw_src, nw_dst */
         MAY_TP_ADDR     = 1 << 1, /* tp_src, tp_dst */
         MAY_NW_PROTO    = 1 << 2, /* nw_proto */
-        MAY_IPVx        = 1 << 3, /* tos, frag */
+        MAY_IPVx        = 1 << 3, /* tos, frag, ttl */
         MAY_ARP_SHA     = 1 << 4, /* arp_sha */
         MAY_ARP_THA     = 1 << 5, /* arp_tha */
         MAY_IPV6_ADDR   = 1 << 6, /* ipv6_src, ipv6_dst */
@@ -2570,6 +2575,7 @@ ofputil_normalize_rule(struct cls_rule *rule, enum nx_flow_format flow_format)
     if (!(may_match & MAY_IPVx)) {
         wc.tos_mask = 0;
         wc.frag_mask = 0;
+        wc.wildcards |= FWW_NW_TTL;
     }
     if (!(may_match & MAY_ARP_SHA)) {
         wc.wildcards |= FWW_ARP_SHA;
index b39eaa155b755fd590cfc4d13021d2dcb332569c..f6eee59a97cdd9a4499056fe048a38fb7529fb19 100644 (file)
@@ -3671,16 +3671,16 @@ commit_set_nw_action(const struct flow *flow, struct flow *base,
     if (base->nw_src == flow->nw_src &&
         base->nw_dst == flow->nw_dst &&
         base->tos == flow->tos &&
+        base->nw_ttl == flow->nw_ttl &&
         base->frag == flow->frag) {
         return;
     }
 
-
-    memset(&ipv4_key, 0, sizeof(ipv4_key));
     ipv4_key.ipv4_src = base->nw_src = flow->nw_src;
     ipv4_key.ipv4_dst = base->nw_dst = flow->nw_dst;
     ipv4_key.ipv4_proto = base->nw_proto;
     ipv4_key.ipv4_tos = flow->tos;
+    ipv4_key.ipv4_ttl = flow->nw_ttl;
     ipv4_key.ipv4_frag = (base->frag == 0 ? OVS_FRAG_TYPE_NONE
                           : base->frag == FLOW_FRAG_ANY ? OVS_FRAG_TYPE_FIRST
                           : OVS_FRAG_TYPE_LATER);
index e2e76d0dad9b31bfd7635d3940d42b5799d8624e..5f300d431070556ce8fee925f5bddbf322bd995e 100644 (file)
@@ -4,24 +4,24 @@ AT_SETUP([OVS datapath parsing and formatting - valid forms])
 AT_DATA([odp-base.txt], [dnl
 in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15)
 in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x1234)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=0x80,frag=no)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=0x81,frag=no)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=0x80,frag=first)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=0x80,frag=later)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=6,tos=0,frag=no),tcp(src=80,dst=8080)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=17,tos=0,frag=no),udp(src=81,dst=6632)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=1,tos=0,frag=no),icmp(type=1,code=2)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tos=0x70,frag=no)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tos=0x71,frag=no)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tos=0x70,frag=first)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tos=0x70,frag=later)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=6,tos=0,frag=no),tcp(src=80,dst=8080)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=17,tos=0,frag=no),udp(src=6630,dst=22)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tos=0,frag=no),icmpv6(type=1,code=2)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tos=0,frag=no),icmpv6(type=135,code=0),nd(target=::3)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tos=0,frag=no),icmpv6(type=135,code=0),nd(target=::3,sll=00:05:06:07:08:09)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tos=0,frag=no),icmpv6(type=136,code=0),nd(target=::3,tll=00:0a:0b:0c:0d:0e)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tos=0,frag=no),icmpv6(type=136,code=0),nd(target=::3,sll=00:05:06:07:08:09,tll=00:0a:0b:0c:0d:0e)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=0x80,ttl=128,frag=no)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=0x81,ttl=128,frag=no)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=0x80,ttl=128,frag=first)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=0x80,ttl=128,frag=later)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=6,tos=0,ttl=128,frag=no),tcp(src=80,dst=8080)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=17,tos=0,ttl=128,frag=no),udp(src=81,dst=6632)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=1,tos=0,ttl=128,frag=no),icmp(type=1,code=2)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tos=0x70,hlimit=128,frag=no)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tos=0x71,hlimit=128,frag=no)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tos=0x70,hlimit=128,frag=first)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tos=0x70,hlimit=128,frag=later)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=6,tos=0,hlimit=128,frag=no),tcp(src=80,dst=8080)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=17,tos=0,hlimit=128,frag=no),udp(src=6630,dst=22)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tos=0,hlimit=128,frag=no),icmpv6(type=1,code=2)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tos=0,hlimit=128,frag=no),icmpv6(type=135,code=0),nd(target=::3)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tos=0,hlimit=128,frag=no),icmpv6(type=135,code=0),nd(target=::3,sll=00:05:06:07:08:09)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tos=0,hlimit=128,frag=no),icmpv6(type=136,code=0),nd(target=::3,tll=00:0a:0b:0c:0d:0e)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tos=0,hlimit=128,frag=no),icmpv6(type=136,code=0),nd(target=::3,sll=00:05:06:07:08:09,tll=00:0a:0b:0c:0d:0e)
 in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0806),arp(sip=1.2.3.4,tip=5.6.7.8,op=1,sha=00:0f:10:11:12:13,tha=00:14:15:16:17:18)
 ])
 
index d8e2f353ac3c89d1e95626124d3177e78d8fa317..df5dc9bfa204b587b30cb2f74a4af2c533eff3c8 100644 (file)
@@ -237,7 +237,7 @@ dnl The tcpdump output format differs slightly from one version to another,
 dnl so trim off the end of the line where differences appear.
 AT_CHECK([sed 's/\(length 60:\).*/\1 .../' stdout], [0], [dnl
 OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=3 data_len=60 buffer=0x00000111
-priority0:tunnel0:in_port0003:tci(0) mac50:54:00:00:00:05->50:54:00:00:00:06 type0800 proto6 tos0 ip192.168.0.1->192.168.0.2 port10031->0
+priority0:tunnel0:in_port0003:tci(0) mac50:54:00:00:00:05->50:54:00:00:00:06 type0800 proto6 tos0 ttl64 ip192.168.0.1->192.168.0.2 port10031->0
 50:54:00:00:00:05 > 50:54:00:00:00:06, ethertype IPv4 (0x0800), length 60: ...
 ])
 AT_CLEANUP
index d08097b626bbcc9721b1168c48d6e0475a89459c..e6c2f922ae91a77848b7b48928db69a2275491a3 100644 (file)
@@ -11,7 +11,7 @@ table=1 in_port=2 priority=1500 icmp actions=output(17),resubmit(,2)
 table=1 in_port=3 priority=1500 icmp actions=output(14),resubmit(,2)
 ])
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
-AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,frag=no),icmp(type=8,code=0)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
   [Datapath actions: 10,11,12,13,14,15,16,17,18,19,20,21
 ])
@@ -36,7 +36,7 @@ in_port=10,reg1=0xdeadbeef actions=output:21
 in_port=11,reg2=0xeef22dea actions=output:22
 ])
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
-AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,frag=no),icmp(type=8,code=0)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
   [Datapath actions: 20,21,22
 ])
@@ -55,7 +55,7 @@ in_port=6 actions=output:NXM_NX_REG0[[0..15]],output:NXM_NX_REG0[[16..31]]
 in_port=7 actions=load:0x110000ff->NXM_NX_REG0[[]],output:NXM_NX_REG0[[]]
 ])
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
-AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,frag=no),icmp(type=8,code=0)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
   [Datapath actions: 9,55,10,55,66,11,77,88
 ])
@@ -73,7 +73,7 @@ in_port=4 actions=set_tunnel:4,set_tunnel:3,output:4
 in_port=5 actions=set_tunnel:5
 ])
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
-AT_CHECK([ovs-appctl ofproto/trace br0 'tun_id(0x1),in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,frag=no),icmp(type=8,code=0)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace br0 'tun_id(0x1),in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
   [Datapath actions: set(tun_id(0x1)),1,2,set(tun_id(0x3)),3,4
 ])
@@ -239,7 +239,7 @@ priority=50 tcp ip_frag=later           actions=output:6
 ])
 AT_CHECK([ovs-ofctl replace-flows br0 flows.txt])
 
-base_flow="in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0"
+base_flow="in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=128"
 no_flow="$base_flow,frag=no),tcp(src=12345,dst=80)"
 first_flow="$base_flow,frag=first),tcp(src=12345,dst=80)"
 later_flow="$base_flow,frag=later)"
@@ -275,15 +275,15 @@ in_port=2 actions=output:12,resubmit:1,output:12
 in_port=3 actions=output:13,resubmit:2,output:14
 ])
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
-AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,frag=no),icmp(type=8,code=0)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
   [Datapath actions: 10
 ])
-AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,frag=no),icmp(type=8,code=0)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
   [Datapath actions: 12,10
 ])
-AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(3),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,frag=no),icmp(type=8,code=0)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(3),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
   [Datapath actions: 13,12,10
 ])
index 39093a80f50239fc366a020cb103034d74903fae..2a458c8df3e13c740bccffd3e738b95b1437d0ae 100644 (file)
@@ -224,6 +224,11 @@ NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(01)
 NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(05)
 NXM_OF_IP_PROTO(05)
 
+# IP TTL
+NXM_OF_ETH_TYPE(0800) NXM_NX_IP_TTL(80)
+NXM_OF_ETH_TYPE(86dd) NXM_NX_IP_TTL(ff)
+NXM_NX_IP_TTL(80)
+
 # IP source
 NXM_OF_ETH_TYPE(0800) NXM_OF_IP_SRC(ac100014)
 NXM_OF_ETH_TYPE(0800) NXM_OF_IP_SRC_W(C0a80000/FFFF0000)
@@ -408,6 +413,11 @@ NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(01)
 NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(05)
 nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
 
+# IP TTL
+NXM_OF_ETH_TYPE(0800), NXM_NX_IP_TTL(80)
+NXM_OF_ETH_TYPE(86dd), NXM_NX_IP_TTL(ff)
+nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
+
 # IP source
 NXM_OF_ETH_TYPE(0800), NXM_OF_IP_SRC(ac100014)
 NXM_OF_ETH_TYPE(0800), NXM_OF_IP_SRC_W(c0a80000/ffff0000)
index 30f9c585280fa748f0b0bb64c7d17acfbaa71c00..cd8d4f207fb4c63c06a611759f26b692d06e3950 100644 (file)
@@ -416,6 +416,15 @@ When \fBdl_type\fR is wildcarded or set to a value other than 0x0800 or
 0x86dd, the value of \fBnw_ecn\fR is ignored (see \fBFlow Syntax\fR
 above).
 .
+.IP \fBnw_ttl=\fIttl\fR
+Matches IP TTL or IPv6 hop limit value \fIttl\fR, which is
+specified as a decimal number between 0 and 255, inclusive.
+.IP
+When \fBdl_type\fR is wildcarded or set to a value other than 0x0800 or
+0x86dd, the value of \fBnw_ttl\fR is ignored (see \fBFlow Syntax\fR
+above).
+.IP
+.
 .IP \fBtp_src=\fIport\fR
 .IQ \fBtp_dst=\fIport\fR
 When \fBdl_type\fR and \fBnw_proto\fR specify TCP or UDP, \fBtp_src\fR