From c4f2731da69eaba5f4bb95583225a5399875f6fc Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Wed, 11 Jan 2012 12:44:23 -0800 Subject: [PATCH] odp-util: Handle ipv6 in set nw action. Rather than silently skipping ipv6 action generation, following patch generates OVS_ACTION_ATTR_SET action for ipv6. Datapath which do not support ipv6 action can reject this action. Bug #8758 Signed-off-by: Pravin B Shelar --- lib/dpif-netdev.c | 2 +- lib/odp-util.c | 65 ++++++++++++++++++++++++++++++++-------- ofproto/ofproto-dpif.c | 7 +++-- utilities/ovs-ofctl.8.in | 2 +- 4 files changed, 59 insertions(+), 17 deletions(-) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index f1d49b69..ad1a39bb 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -1153,6 +1153,7 @@ execute_set_action(struct ofpbuf *packet, const struct nlattr *a) switch (type) { case OVS_KEY_ATTR_TUN_ID: case OVS_KEY_ATTR_PRIORITY: + case OVS_KEY_ATTR_IPV6: /* not implemented */ break; @@ -1180,7 +1181,6 @@ execute_set_action(struct ofpbuf *packet, const struct nlattr *a) case OVS_KEY_ATTR_UNSPEC: case OVS_KEY_ATTR_ENCAP: case OVS_KEY_ATTR_ETHERTYPE: - case OVS_KEY_ATTR_IPV6: case OVS_KEY_ATTR_IN_PORT: case OVS_KEY_ATTR_VLAN: case OVS_KEY_ATTR_ICMP: diff --git a/lib/odp-util.c b/lib/odp-util.c index bfc1937c..ffb486ec 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -1136,11 +1136,11 @@ odp_flow_key_from_string(const char *s, const struct shash *port_names, } static uint8_t -ovs_to_odp_frag(uint8_t ovs_frag) +ovs_to_odp_frag(uint8_t nw_frag) { - return (ovs_frag & FLOW_NW_FRAG_LATER ? OVS_FRAG_TYPE_LATER - : ovs_frag & FLOW_NW_FRAG_ANY ? OVS_FRAG_TYPE_FIRST - : OVS_FRAG_TYPE_NONE); + return (nw_frag == 0 ? OVS_FRAG_TYPE_NONE + : nw_frag == FLOW_NW_FRAG_ANY ? OVS_FRAG_TYPE_FIRST + : OVS_FRAG_TYPE_LATER); } /* Appends a representation of 'flow' as OVS_KEY_ATTR_* attributes to 'buf'. */ @@ -1778,16 +1778,11 @@ commit_vlan_action(const struct flow *flow, struct flow *base, } static void -commit_set_nw_action(const struct flow *flow, struct flow *base, +commit_set_ipv4_action(const struct flow *flow, struct flow *base, struct ofpbuf *odp_actions) { struct ovs_key_ipv4 ipv4_key; - if (base->dl_type != htons(ETH_TYPE_IP) || - !base->nw_src || !base->nw_dst) { - return; - } - if (base->nw_src == flow->nw_src && base->nw_dst == flow->nw_dst && base->nw_tos == flow->nw_tos && @@ -1801,14 +1796,58 @@ commit_set_nw_action(const struct flow *flow, struct flow *base, ipv4_key.ipv4_tos = base->nw_tos = flow->nw_tos; ipv4_key.ipv4_ttl = base->nw_ttl = flow->nw_ttl; ipv4_key.ipv4_proto = base->nw_proto; - ipv4_key.ipv4_frag = (base->nw_frag == 0 ? OVS_FRAG_TYPE_NONE - : base->nw_frag == FLOW_NW_FRAG_ANY - ? OVS_FRAG_TYPE_FIRST : OVS_FRAG_TYPE_LATER); + ipv4_key.ipv4_frag = ovs_to_odp_frag(base->nw_frag); commit_set_action(odp_actions, OVS_KEY_ATTR_IPV4, &ipv4_key, sizeof(ipv4_key)); } +static void +commit_set_ipv6_action(const struct flow *flow, struct flow *base, + struct ofpbuf *odp_actions) +{ + struct ovs_key_ipv6 ipv6_key; + + if (ipv6_addr_equals(&base->ipv6_src, &flow->ipv6_src) && + ipv6_addr_equals(&base->ipv6_dst, &flow->ipv6_dst) && + base->ipv6_label == flow->ipv6_label && + base->nw_tos == flow->nw_tos && + base->nw_ttl == flow->nw_ttl && + base->nw_frag == flow->nw_frag) { + return; + } + + base->ipv6_src = flow->ipv6_src; + memcpy(&ipv6_key.ipv6_src, &base->ipv6_src, sizeof(ipv6_key.ipv6_src)); + base->ipv6_dst = flow->ipv6_dst; + memcpy(&ipv6_key.ipv6_dst, &base->ipv6_dst, sizeof(ipv6_key.ipv6_dst)); + + ipv6_key.ipv6_label = base->ipv6_label = flow->ipv6_label; + ipv6_key.ipv6_tclass = base->nw_tos = flow->nw_tos; + ipv6_key.ipv6_hlimit = base->nw_ttl = flow->nw_ttl; + ipv6_key.ipv6_proto = base->nw_proto; + ipv6_key.ipv6_frag = ovs_to_odp_frag(base->nw_frag); + + commit_set_action(odp_actions, OVS_KEY_ATTR_IPV6, + &ipv6_key, sizeof(ipv6_key)); +} + +static void +commit_set_nw_action(const struct flow *flow, struct flow *base, + struct ofpbuf *odp_actions) +{ + /* Check if flow really have an IP header. */ + if (!flow->nw_proto) { + return; + } + + if (base->dl_type == htons(ETH_TYPE_IP)) { + commit_set_ipv4_action(flow, base, odp_actions); + } else if (base->dl_type == htons(ETH_TYPE_IPV6)) { + commit_set_ipv6_action(flow, base, odp_actions); + } +} + static void commit_set_port_action(const struct flow *flow, struct flow *base, struct ofpbuf *odp_actions) diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index e206f431..60f81755 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -4634,8 +4634,11 @@ do_xlate_actions(const union ofp_action *in, size_t n_in, break; case OFPUTIL_OFPAT_SET_NW_TOS: - ctx->flow.nw_tos &= ~IP_DSCP_MASK; - ctx->flow.nw_tos |= ia->nw_tos.nw_tos & IP_DSCP_MASK; + /* OpenFlow 1.0 only supports IPv4. */ + if (ctx->flow.dl_type == htons(ETH_TYPE_IP)) { + ctx->flow.nw_tos &= ~IP_DSCP_MASK; + ctx->flow.nw_tos |= ia->nw_tos.nw_tos & IP_DSCP_MASK; + } break; case OFPUTIL_OFPAT_SET_TP_SRC: diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index 9ad9554f..4bfd5436 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -737,7 +737,7 @@ Sets the TCP or UDP source port to \fIport\fR. Sets the TCP or UDP destination port to \fIport\fR. . .IP \fBmod_nw_tos\fB:\fItos\fR -Sets the IP ToS/DSCP field to \fItos\fR. Valid values are between 0 and +Sets the IPv4 ToS/DSCP field to \fItos\fR. Valid values are between 0 and 255, inclusive. Note that the two lower reserved bits are never modified. . -- 2.30.2