From: Jesse Gross Date: Mon, 12 Apr 2010 15:49:16 +0000 (-0400) Subject: tunneling: Add support for tunnel ID. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=659586efcf6f9539282da9447007897907c41112;p=openvswitch tunneling: Add support for tunnel ID. Add a tun_id field which contains the ID of the encapsulating tunnel on which a packet was received (0 if not received on a tunnel). Also add an action which allows the tunnel ID to be set for outgoing packets. At this point there aren't any tunnel implementations so these fields don't have any effect. The matching is exposed to OpenFlow by overloading the high 32 bits of the cookie as the tunnel ID. ovs-ofctl is capable of turning on this special behavior using a new "tun-cookie" command but this command is intentially undocumented to avoid it being used without a full understanding of the consequences. --- diff --git a/datapath/actions.c b/datapath/actions.c index bef7d108..10324619 100644 --- a/datapath/actions.c +++ b/datapath/actions.c @@ -58,6 +58,11 @@ make_writable(struct sk_buff *skb, unsigned min_headroom, gfp_t gfp) return NULL; } +static void set_tunnel(struct sk_buff *skb, struct odp_flow_key *key, + __be32 tun_id) +{ + OVS_CB(skb)->tun_id = key->tun_id = tun_id; +} static struct sk_buff * vlan_pull_tag(struct sk_buff *skb) @@ -477,6 +482,8 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb, } } + OVS_CB(skb)->tun_id = 0; + for (; n_actions > 0; a++, n_actions--) { WARN_ON_ONCE(skb_shared(skb)); if (prev_port != -1) { @@ -502,6 +509,10 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb, } break; + case ODPAT_SET_TUNNEL: + set_tunnel(skb, key, a->tunnel.tun_id); + break; + case ODPAT_SET_VLAN_VID: case ODPAT_SET_VLAN_PCP: skb = modify_vlan_tci(dp, skb, key, a, n_actions, gfp); diff --git a/datapath/datapath.c b/datapath/datapath.c index 6365f947..9dfd6042 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -537,6 +537,7 @@ void dp_process_received_packet(struct sk_buff *skb, struct net_bridge_port *p) WARN_ON_ONCE(skb_shared(skb)); compute_ip_summed(skb, false); + OVS_CB(skb)->tun_id = 0; /* BHs are off so we don't have to use get_cpu()/put_cpu() here. */ stats = percpu_ptr(dp->stats_percpu, smp_processor_id()); @@ -558,7 +559,7 @@ void dp_process_received_packet(struct sk_buff *skb, struct net_bridge_port *p) stats->n_hit++; } else { stats->n_missed++; - dp_output_control(dp, skb, _ODPL_MISS_NR, 0); + dp_output_control(dp, skb, _ODPL_MISS_NR, OVS_CB(skb)->tun_id); } } @@ -1302,6 +1303,7 @@ static int do_execute(struct datapath *dp, const struct odp_execute *executep) skb = alloc_skb(execute.length, GFP_KERNEL); if (!skb) goto error_free_actions; + if (execute.in_port < DP_MAX_PORTS) { struct net_bridge_port *p = dp->ports[execute.in_port]; if (p) diff --git a/datapath/datapath.h b/datapath/datapath.h index 38c84756..faf24704 100644 --- a/datapath/datapath.h +++ b/datapath/datapath.h @@ -195,7 +195,8 @@ enum csum_type { * kernel versions. */ struct ovs_skb_cb { - enum csum_type ip_summed; + enum csum_type ip_summed; + __be32 tun_id; }; #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb) diff --git a/datapath/flow.c b/datapath/flow.c index 9a94d0ba..094a2c8d 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -202,8 +202,9 @@ int flow_extract(struct sk_buff *skb, u16 in_port, struct odp_flow_key *key) int nh_ofs; memset(key, 0, sizeof *key); - key->dl_vlan = htons(ODP_VLAN_NONE); + key->tun_id = OVS_CB(skb)->tun_id; key->in_port = in_port; + key->dl_vlan = htons(ODP_VLAN_NONE); if (skb->len < sizeof *eth) return 0; diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index 17d86a86..5ec009a7 100644 --- a/include/openflow/nicira-ext.h +++ b/include/openflow/nicira-ext.h @@ -45,6 +45,10 @@ enum nicira_type { NXT_FLOW_END_CONFIG__OBSOLETE, NXT_FLOW_END__OBSOLETE, NXT_MGMT__OBSOLETE, + + /* Use the high 32 bits of the cookie field as the tunnel ID in the flow + * match. */ + NXT_TUN_ID_FROM_COOKIE, }; struct nicira_header { @@ -54,6 +58,14 @@ struct nicira_header { }; OFP_ASSERT(sizeof(struct nicira_header) == 16); +struct nxt_tun_id_cookie { + struct ofp_header header; + uint32_t vendor; /* NX_VENDOR_ID. */ + uint32_t subtype; /* NXT_TUN_ID_FROM_COOKIE */ + uint8_t set; /* Nonzero to enable, zero to disable. */ + uint8_t pad[7]; +}; +OFP_ASSERT(sizeof(struct nxt_tun_id_cookie) == 24); enum nx_action_subtype { NXAST_SNAT__OBSOLETE, /* No longer used. */ @@ -80,13 +92,15 @@ enum nx_action_subtype { * * NXAST_RESUBMIT may be used any number of times within a set of actions. */ - NXAST_RESUBMIT + NXAST_RESUBMIT, + + NXAST_SET_TUNNEL /* Set encapsulating tunnel ID. */ }; /* Action structure for NXAST_RESUBMIT. */ struct nx_action_resubmit { uint16_t type; /* OFPAT_VENDOR. */ - uint16_t len; /* Length is 8. */ + uint16_t len; /* Length is 16. */ uint32_t vendor; /* NX_VENDOR_ID. */ uint16_t subtype; /* NXAST_RESUBMIT. */ uint16_t in_port; /* New in_port for checking flow table. */ @@ -94,14 +108,31 @@ struct nx_action_resubmit { }; OFP_ASSERT(sizeof(struct nx_action_resubmit) == 16); +/* Action structure for NXAST_SET_TUNNEL. */ +struct nx_action_set_tunnel { + uint16_t type; /* OFPAT_VENDOR. */ + uint16_t len; /* Length is 16. */ + uint32_t vendor; /* NX_VENDOR_ID. */ + uint16_t subtype; /* NXAST_SET_TUNNEL. */ + uint8_t pad[2]; + uint32_t tun_id; /* Tunnel ID. */ +}; +OFP_ASSERT(sizeof(struct nx_action_set_tunnel) == 16); + /* Header for Nicira-defined actions. */ struct nx_action_header { uint16_t type; /* OFPAT_VENDOR. */ - uint16_t len; /* Length is 8. */ + uint16_t len; /* Length is 16. */ uint32_t vendor; /* NX_VENDOR_ID. */ uint16_t subtype; /* NXAST_*. */ uint8_t pad[6]; }; OFP_ASSERT(sizeof(struct nx_action_header) == 16); +/* Wildcard for tunnel ID. */ +#define NXFW_TUN_ID (1 << 25) + +#define NXFW_ALL NXFW_TUN_ID +#define OVSFW_ALL (OFPFW_ALL | NXFW_ALL) + #endif /* openflow/nicira-ext.h */ diff --git a/include/openvswitch/datapath-protocol.h b/include/openvswitch/datapath-protocol.h index 6c535454..6ddff014 100644 --- a/include/openvswitch/datapath-protocol.h +++ b/include/openvswitch/datapath-protocol.h @@ -127,7 +127,8 @@ struct odp_stats { * @arg: Argument value whose meaning depends on @type. * * For @type == %_ODPL_MISS_NR, the header is followed by packet data. The - * @arg member is unused and set to 0. + * @arg member is the ID (in network byte order) of the tunnel that + * encapsulated this packet. It is 0 if the packet was not received on a tunnel. * * For @type == %_ODPL_ACTION_NR, the header is followed by packet data. The * @arg member is copied from the &struct odp_action_controller that caused @@ -191,6 +192,7 @@ struct odp_flow_stats { }; struct odp_flow_key { + __be32 tun_id; /* Encapsulating tunnel ID. */ __be32 nw_src; /* IP source address. */ __be32 nw_dst; /* IP destination address. */ __u16 in_port; /* Input switch port. */ @@ -253,7 +255,8 @@ struct odp_flowvec { #define ODPAT_SET_NW_TOS 10 /* IP ToS/DSCP field (6 bits). */ #define ODPAT_SET_TP_SRC 11 /* TCP/UDP source port. */ #define ODPAT_SET_TP_DST 12 /* TCP/UDP destination port. */ -#define ODPAT_N_ACTIONS 13 +#define ODPAT_SET_TUNNEL 13 /* Set the encapsulating tunnel ID. */ +#define ODPAT_N_ACTIONS 14 struct odp_action_output { __u16 type; /* ODPAT_OUTPUT. */ @@ -275,6 +278,12 @@ struct odp_action_controller { __u32 arg; /* Copied to struct odp_msg 'arg' member. */ }; +struct odp_action_tunnel { + __u16 type; /* ODPAT_SET_TUNNEL. */ + __u16 reserved; + __be32 tun_id; /* Tunnel ID. */ +}; + /* Action structure for ODPAT_SET_VLAN_VID. */ struct odp_action_vlan_vid { __u16 type; /* ODPAT_SET_VLAN_VID. */ @@ -326,6 +335,7 @@ union odp_action { struct odp_action_output output; struct odp_action_output_group output_group; struct odp_action_controller controller; + struct odp_action_tunnel tunnel; struct odp_action_vlan_vid vlan_vid; struct odp_action_vlan_pcp vlan_pcp; struct odp_action_dl_addr dl_addr; diff --git a/lib/classifier.c b/lib/classifier.c index ee78dadd..4bd89421 100644 --- a/lib/classifier.c +++ b/lib/classifier.c @@ -55,8 +55,8 @@ static bool rules_match_2wild(const struct cls_rule *wild1, /* Converts the flow in 'flow' into a cls_rule in 'rule', with the given * 'wildcards' and 'priority'.*/ void -cls_rule_from_flow(struct cls_rule *rule, const flow_t *flow, - uint32_t wildcards, unsigned int priority) +cls_rule_from_flow(const flow_t *flow, uint32_t wildcards, + unsigned int priority, struct cls_rule *rule) { assert(!flow->reserved[0] && !flow->reserved[1] && !flow->reserved[2]); rule->flow = *flow; @@ -66,13 +66,15 @@ cls_rule_from_flow(struct cls_rule *rule, const flow_t *flow, } /* Converts the ofp_match in 'match' into a cls_rule in 'rule', with the given - * 'priority'. */ + * 'priority'. If 'tun_id_from_cookie' is set then the upper 32 bits of + * 'cookie' are stored in the rule as the tunnel ID. */ void -cls_rule_from_match(struct cls_rule *rule, const struct ofp_match *match, - unsigned int priority) +cls_rule_from_match(const struct ofp_match *match, unsigned int priority, + bool tun_id_from_cookie, uint64_t cookie, + struct cls_rule *rule) { uint32_t wildcards; - flow_from_match(&rule->flow, &wildcards, match); + flow_from_match(match, tun_id_from_cookie, cookie, &rule->flow, &wildcards); flow_wildcards_init(&rule->wc, wildcards); rule->priority = rule->wc.wildcards ? priority : UINT16_MAX; rule->table_idx = table_idx_from_wildcards(rule->wc.wildcards); @@ -305,7 +307,7 @@ classifier_lookup_wild(const struct classifier *cls, const flow_t *flow) struct cls_rule target; int i; - cls_rule_from_flow(&target, flow, 0, 0); + cls_rule_from_flow(flow, 0, 0, &target); for (i = 0; i < CLS_N_FIELDS; i++) { struct cls_rule *rule = search_table(&cls->tables[i], i, &target); if (rule && (!best || rule->priority > best->priority)) { @@ -330,7 +332,7 @@ classifier_find_rule_exactly(const struct classifier *cls, return search_exact_table(cls, flow_hash(target, 0), target); } - assert(wildcards == (wildcards & OFPFW_ALL)); + assert(wildcards == (wildcards & OVSFW_ALL)); table_idx = table_idx_from_wildcards(wildcards); hash = hash_fields(target, table_idx); HMAP_FOR_EACH_WITH_HASH (bucket, struct cls_bucket, hmap_node, hash, @@ -367,7 +369,7 @@ classifier_rule_overlaps(const struct classifier *cls, true : false; } - cls_rule_from_flow(&target_rule, target, wildcards, priority); + cls_rule_from_flow(target, wildcards, priority, &target_rule); for (tbl = &cls->tables[0]; tbl < &cls->tables[CLS_N_FIELDS]; tbl++) { struct cls_bucket *bucket; diff --git a/lib/classifier.h b/lib/classifier.h index 126d1498..35516022 100644 --- a/lib/classifier.h +++ b/lib/classifier.h @@ -44,10 +44,11 @@ #include "flow.h" #include "hmap.h" #include "list.h" +#include "openflow/nicira-ext.h" #include "openflow/openflow.h" /* Number of bytes of fields in a rule. */ -#define CLS_N_BYTES 31 +#define CLS_N_BYTES 37 /* Fields in a rule. * @@ -59,6 +60,7 @@ /* wildcard bit(s) member name name */ \ /* ----------------- ----------- -------- */ \ CLS_FIELD(OFPFW_IN_PORT, in_port, IN_PORT) \ + CLS_FIELD(NXFW_TUN_ID, tun_id, TUN_ID) \ CLS_FIELD(OFPFW_DL_VLAN, dl_vlan, DL_VLAN) \ CLS_FIELD(OFPFW_DL_VLAN_PCP, dl_vlan_pcp, DL_VLAN_PCP) \ CLS_FIELD(OFPFW_DL_SRC, dl_src, DL_SRC) \ @@ -121,10 +123,11 @@ struct cls_rule { unsigned int table_idx; /* Index into struct classifier 'tables'. */ }; -void cls_rule_from_flow(struct cls_rule *, const flow_t *, uint32_t wildcards, - unsigned int priority); -void cls_rule_from_match(struct cls_rule *, const struct ofp_match *, - unsigned int priority); +void cls_rule_from_flow(const flow_t *, uint32_t wildcards, + unsigned int priority, struct cls_rule *); +void cls_rule_from_match(const struct ofp_match *, unsigned int priority, + bool tun_id_from_cookie, uint64_t cookie, + struct cls_rule *); char *cls_rule_to_string(const struct cls_rule *); void cls_rule_print(const struct cls_rule *); void cls_rule_moved(struct classifier *, diff --git a/lib/dhcp-client.c b/lib/dhcp-client.c index 30ac56c9..0abf115b 100644 --- a/lib/dhcp-client.c +++ b/lib/dhcp-client.c @@ -931,7 +931,7 @@ do_receive_msg(struct dhclient *cli, struct dhcp_msg *msg) goto drained; } - flow_extract(&b, 0, &flow); + flow_extract(&b, 0, 0, &flow); if (flow.dl_type != htons(ETH_TYPE_IP) || flow.nw_proto != IP_TYPE_UDP || flow.tp_dst != htons(DHCP_CLIENT_PORT) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 1cc4ed46..7d31a69b 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -932,7 +932,7 @@ dpif_netdev_execute(struct dpif *dpif, uint16_t in_port, * if we don't. */ copy = *packet; } - flow_extract(©, in_port, &flow); + flow_extract(©, 0, in_port, &flow); error = dp_netdev_execute_actions(dp, ©, &flow, actions, n_actions); if (mutates) { ofpbuf_uninit(©); @@ -1026,7 +1026,7 @@ dp_netdev_port_input(struct dp_netdev *dp, struct dp_netdev_port *port, struct dp_netdev_flow *flow; flow_t key; - if (flow_extract(packet, port->port_no, &key) && dp->drop_frags) { + if (flow_extract(packet, 0, port->port_no, &key) && dp->drop_frags) { dp->n_frags++; return; } diff --git a/lib/flow.c b/lib/flow.c index 7d368bb6..700e7f81 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -27,6 +27,7 @@ #include "openflow/openflow.h" #include "openvswitch/datapath-protocol.h" #include "packets.h" +#include "xtoxll.h" #include "vlog.h" #define THIS_MODULE VLM_flow @@ -87,9 +88,12 @@ pull_vlan(struct ofpbuf *packet) return ofpbuf_try_pull(packet, VLAN_HEADER_LEN); } -/* Returns 1 if 'packet' is an IP fragment, 0 otherwise. */ +/* Returns 1 if 'packet' is an IP fragment, 0 otherwise. + * 'tun_id' is in network byte order, while 'in_port' is in host byte order. + * These byte orders are the same as they are in struct odp_flow_key. */ int -flow_extract(struct ofpbuf *packet, uint16_t in_port, flow_t *flow) +flow_extract(struct ofpbuf *packet, uint32_t tun_id, uint16_t in_port, + flow_t *flow) { struct ofpbuf b = *packet; struct eth_header *eth; @@ -98,8 +102,9 @@ flow_extract(struct ofpbuf *packet, uint16_t in_port, flow_t *flow) COVERAGE_INC(flow_extract); memset(flow, 0, sizeof *flow); - flow->dl_vlan = htons(OFP_VLAN_NONE); + flow->tun_id = tun_id; flow->in_port = in_port; + flow->dl_vlan = htons(OFP_VLAN_NONE); packet->l2 = b.data; packet->l3 = NULL; @@ -240,9 +245,14 @@ flow_extract_stats(const flow_t *flow, struct ofpbuf *packet, /* Extract 'flow' with 'wildcards' into the OpenFlow match structure * 'match'. */ void -flow_to_match(const flow_t *flow, uint32_t wildcards, struct ofp_match *match) +flow_to_match(const flow_t *flow, uint32_t wildcards, bool tun_id_from_cookie, + struct ofp_match *match) { + if (!tun_id_from_cookie) { + wildcards &= OFPFW_ALL; + } match->wildcards = htonl(wildcards); + match->in_port = htons(flow->in_port == ODPP_LOCAL ? OFPP_LOCAL : flow->in_port); match->dl_vlan = flow->dl_vlan; @@ -261,14 +271,21 @@ flow_to_match(const flow_t *flow, uint32_t wildcards, struct ofp_match *match) } void -flow_from_match(flow_t *flow, uint32_t *wildcards, - const struct ofp_match *match) +flow_from_match(const struct ofp_match *match, bool tun_id_from_cookie, + uint64_t cookie, flow_t *flow, uint32_t *wildcards) { if (wildcards) { *wildcards = ntohl(match->wildcards); + + if (!tun_id_from_cookie) { + *wildcards |= NXFW_TUN_ID; + } } flow->nw_src = match->nw_src; flow->nw_dst = match->nw_dst; + if (tun_id_from_cookie) { + flow->tun_id = htonl(ntohll(cookie) >> 32); + } flow->in_port = (match->in_port == htons(OFPP_LOCAL) ? ODPP_LOCAL : ntohs(match->in_port)); flow->dl_vlan = match->dl_vlan; @@ -294,14 +311,27 @@ flow_to_string(const flow_t *flow) void flow_format(struct ds *ds, const flow_t *flow) { - ds_put_format(ds, "in_port%04x:vlan%d:pcp%d mac"ETH_ADDR_FMT - "->"ETH_ADDR_FMT" type%04x proto%"PRId8" tos%"PRIu8 - " ip"IP_FMT"->"IP_FMT" port%d->%d", - flow->in_port, ntohs(flow->dl_vlan), flow->dl_vlan_pcp, - ETH_ADDR_ARGS(flow->dl_src), ETH_ADDR_ARGS(flow->dl_dst), - ntohs(flow->dl_type), flow->nw_proto, flow->nw_tos, - IP_ARGS(&flow->nw_src), IP_ARGS(&flow->nw_dst), - ntohs(flow->tp_src), ntohs(flow->tp_dst)); + ds_put_format(ds, "tunnel%08"PRIx32":in_port%04"PRIx16 + ":vlan%"PRIu16":pcp%"PRIu8 + " mac"ETH_ADDR_FMT"->"ETH_ADDR_FMT + " type%04"PRIx16 + " proto%"PRIu8 + " tos%"PRIu8 + " ip"IP_FMT"->"IP_FMT + " port%"PRIu16"->%"PRIu16, + ntohl(flow->tun_id), + flow->in_port, + ntohs(flow->dl_vlan), + flow->dl_vlan_pcp, + ETH_ADDR_ARGS(flow->dl_src), + ETH_ADDR_ARGS(flow->dl_dst), + ntohs(flow->dl_type), + flow->nw_proto, + flow->nw_tos, + IP_ARGS(&flow->nw_src), + IP_ARGS(&flow->nw_dst), + ntohs(flow->tp_src), + ntohs(flow->tp_dst)); } void diff --git a/lib/flow.h b/lib/flow.h index ca140afa..058404c8 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -21,9 +21,9 @@ #include #include #include +#include "openflow/nicira-ext.h" #include "openflow/openflow.h" #include "hash.h" -#include "openflow/openflow.h" #include "openvswitch/datapath-protocol.h" #include "util.h" @@ -33,11 +33,13 @@ struct ofpbuf; typedef struct odp_flow_key flow_t; -int flow_extract(struct ofpbuf *, uint16_t in_port, flow_t *); +int flow_extract(struct ofpbuf *, uint32_t tun_id, uint16_t in_port, flow_t *); void flow_extract_stats(const flow_t *flow, struct ofpbuf *packet, struct odp_flow_stats *stats); -void flow_to_match(const flow_t *, uint32_t wildcards, struct ofp_match *); -void flow_from_match(flow_t *, uint32_t *wildcards, const struct ofp_match *); +void flow_to_match(const flow_t *, uint32_t wildcards, bool tun_id_cookie, + struct ofp_match *); +void flow_from_match(const struct ofp_match *, bool tun_id_from_cookie, + uint64_t cookie, flow_t *, uint32_t *wildcards); char *flow_to_string(const flow_t *); void flow_format(struct ds *, const flow_t *); void flow_print(FILE *, const flow_t *); @@ -94,7 +96,7 @@ flow_nw_bits_to_mask(uint32_t wildcards, int shift) static inline void flow_wildcards_init(struct flow_wildcards *wc, uint32_t wildcards) { - wc->wildcards = wildcards & OFPFW_ALL; + wc->wildcards = wildcards & OVSFW_ALL; wc->nw_src_mask = flow_nw_bits_to_mask(wc->wildcards, OFPFW_NW_SRC_SHIFT); wc->nw_dst_mask = flow_nw_bits_to_mask(wc->wildcards, OFPFW_NW_DST_SHIFT); } diff --git a/lib/learning-switch.c b/lib/learning-switch.c index 092274cb..126cc6b8 100644 --- a/lib/learning-switch.c +++ b/lib/learning-switch.c @@ -404,7 +404,7 @@ process_packet_in(struct lswitch *sw, struct rconn *rconn, void *opi_) pkt_len = ntohs(opi->header.length) - pkt_ofs; pkt.data = opi->data; pkt.size = pkt_len; - flow_extract(&pkt, in_port, &flow); + flow_extract(&pkt, 0, in_port, &flow); if (may_learn(sw, in_port) && sw->ml) { if (mac_learning_learn(sw->ml, flow.dl_src, 0, in_port)) { diff --git a/lib/odp-util.c b/lib/odp-util.c index 67ce4132..67d1b3ee 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -55,6 +55,9 @@ format_odp_action(struct ds *ds, const union odp_action *a) case ODPAT_CONTROLLER: ds_put_format(ds, "ctl(%"PRIu32")", a->controller.arg); break; + case ODPAT_SET_TUNNEL: + ds_put_format(ds, "set_tunnel(0x%08"PRIx32")", ntohl(a->tunnel.tun_id)); + break; case ODPAT_SET_VLAN_VID: ds_put_format(ds, "set_vlan(%"PRIu16")", ntohs(a->vlan_vid.vlan_vid)); break; diff --git a/lib/ofp-print.c b/lib/ofp-print.c index bcaf2307..7c1ebd00 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -134,8 +134,8 @@ ofp_packet_in(struct ds *string, const void *oh, size_t len, int verbosity) struct ofp_match match; packet.data = (void *) op->data; packet.size = data_len; - flow_extract(&packet, ntohs(op->in_port), &flow); - flow_to_match(&flow, 0, &match); + flow_extract(&packet, 0, ntohs(op->in_port), &flow); + flow_to_match(&flow, 0, false, &match); ofp_print_match(string, &match, verbosity); ds_put_char(string, '\n'); } @@ -193,6 +193,13 @@ ofp_print_nx_action(struct ds *string, const struct nx_action_header *nah) break; } + case NXAST_SET_TUNNEL: { + const struct nx_action_set_tunnel *nast = + (struct nx_action_set_tunnel *)nah; + ds_put_format(string, "set_tunnel:0x%08"PRIx32, ntohl(nast->tun_id)); + break; + } + default: ds_put_format(string, "***unknown Nicira action:%d***\n", ntohs(nah->subtype)); @@ -672,6 +679,9 @@ ofp_match_to_string(const struct ofp_match *om, int verbosity) skip_type = false; } } + if (w & NXFW_TUN_ID) { + ds_put_cstr(&f, "tun_id_wild,"); + } print_wild(&f, "in_port=", w & OFPFW_IN_PORT, verbosity, "%d", ntohs(om->in_port)); print_wild(&f, "dl_vlan=", w & OFPFW_DL_VLAN, verbosity, diff --git a/lib/vconn.c b/lib/vconn.c index 99d5a54d..80ba471b 100644 --- a/lib/vconn.c +++ b/lib/vconn.c @@ -1358,6 +1358,7 @@ check_nicira_action(const union ofp_action *a, unsigned int len) switch (ntohs(nah->subtype)) { case NXAST_RESUBMIT: + case NXAST_SET_TUNNEL: return check_action_exact_len(a, len, 16); default: return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR_TYPE); @@ -1466,7 +1467,7 @@ normalize_match(struct ofp_match *m) enum { OFPFW_TP = OFPFW_TP_SRC | OFPFW_TP_DST }; uint32_t wc; - wc = ntohl(m->wildcards) & OFPFW_ALL; + wc = ntohl(m->wildcards) & OVSFW_ALL; if (wc & OFPFW_DL_TYPE) { m->dl_type = 0; diff --git a/ofproto/fail-open.c b/ofproto/fail-open.c index ff77de87..e866c571 100644 --- a/ofproto/fail-open.c +++ b/ofproto/fail-open.c @@ -173,7 +173,7 @@ fail_open_recover(struct fail_open *fo) fo->next_bogus_packet_in = LLONG_MAX; memset(&flow, 0, sizeof flow); - ofproto_delete_flow(fo->ofproto, &flow, OFPFW_ALL, FAIL_OPEN_PRIORITY); + ofproto_delete_flow(fo->ofproto, &flow, OVSFW_ALL, FAIL_OPEN_PRIORITY); } } @@ -201,7 +201,7 @@ fail_open_flushed(struct fail_open *fo) action.output.len = htons(sizeof action); action.output.port = htons(OFPP_NORMAL); memset(&flow, 0, sizeof flow); - ofproto_add_flow(fo->ofproto, &flow, OFPFW_ALL, FAIL_OPEN_PRIORITY, + ofproto_add_flow(fo->ofproto, &flow, OVSFW_ALL, FAIL_OPEN_PRIORITY, &action, 1, 0); } } diff --git a/ofproto/in-band.c b/ofproto/in-band.c index 857618fd..2118809e 100644 --- a/ofproto/in-band.c +++ b/ofproto/in-band.c @@ -370,7 +370,7 @@ set_up_flow(struct in_band *in_band, int rule_idx, const flow_t *flow, rule->installed = true; rule->flow = *flow; - rule->wildcards = OFPFW_ALL & ~fixed_fields; + rule->wildcards = OVSFW_ALL & ~fixed_fields; rule->priority = IB_BASE_PRIORITY + (N_IB_RULES - rule_idx); action.type = htons(OFPAT_OUTPUT); diff --git a/ofproto/ofproto-sflow.c b/ofproto/ofproto-sflow.c index 45372003..85f9f9ff 100644 --- a/ofproto/ofproto-sflow.c +++ b/ofproto/ofproto-sflow.c @@ -496,7 +496,7 @@ ofproto_sflow_received(struct ofproto_sflow *os, struct odp_msg *msg) /* Get packet payload and extract flow. */ payload.data = (union odp_action *) (actions + n_actions); payload.size = msg->length - min_size; - flow_extract(&payload, msg->port, &flow); + flow_extract(&payload, 0, msg->port, &flow); /* Build a flow sample */ memset(&fs, 0, sizeof fs); diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 3b5cf486..995e6b0f 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -219,6 +219,7 @@ struct ofproto { bool need_revalidate; long long int next_expiration; struct tag_set revalidate_set; + bool tun_id_from_cookie; /* OpenFlow connections. */ struct list all_conns; @@ -1029,7 +1030,7 @@ ofproto_add_flow(struct ofproto *p, rule = rule_create(p, NULL, actions, n_actions, idle_timeout >= 0 ? idle_timeout : 5 /* XXX */, 0, 0, false); - cls_rule_from_flow(&rule->cr, flow, wildcards, priority); + cls_rule_from_flow(flow, wildcards, priority, &rule->cr); rule_insert(p, rule, NULL, 0); } @@ -1583,7 +1584,7 @@ rule_insert(struct ofproto *p, struct rule *rule, struct ofpbuf *packet, /* Send the packet and credit it to the rule. */ if (packet) { flow_t flow; - flow_extract(packet, in_port, &flow); + flow_extract(packet, 0, in_port, &flow); rule_execute(p, rule, packet, &flow); } @@ -1610,9 +1611,8 @@ rule_create_subrule(struct ofproto *ofproto, struct rule *rule, rule->idle_timeout, rule->hard_timeout, 0, false); COVERAGE_INC(ofproto_subrule_create); - cls_rule_from_flow(&subrule->cr, flow, 0, - (rule->cr.priority <= UINT16_MAX ? UINT16_MAX - : rule->cr.priority)); + cls_rule_from_flow(flow, 0, (rule->cr.priority <= UINT16_MAX ? UINT16_MAX + : rule->cr.priority), &subrule->cr); classifier_insert_exact(&ofproto->cls, &subrule->cr); return subrule; @@ -2146,6 +2146,8 @@ xlate_nicira_action(struct action_xlate_ctx *ctx, const struct nx_action_header *nah) { const struct nx_action_resubmit *nar; + const struct nx_action_set_tunnel *nast; + union odp_action *oa; int subtype = ntohs(nah->subtype); assert(nah->vendor == htonl(NX_VENDOR_ID)); @@ -2155,6 +2157,12 @@ xlate_nicira_action(struct action_xlate_ctx *ctx, xlate_table_action(ctx, ofp_port_to_odp_port(ntohs(nar->in_port))); break; + case NXAST_SET_TUNNEL: + nast = (const struct nx_action_set_tunnel *) nah; + oa = odp_actions_add(ctx->out, ODPAT_SET_TUNNEL); + ctx->flow.tun_id = oa->tunnel.tun_id = nast->tun_id; + break; + /* If you add a new action here that modifies flow data, don't forget to * update the flow key in ctx->flow in the same key. */ @@ -2327,7 +2335,7 @@ handle_packet_out(struct ofproto *p, struct ofconn *ofconn, buffer = NULL; } - flow_extract(&payload, ofp_port_to_odp_port(ntohs(opo->in_port)), &flow); + flow_extract(&payload, 0, ofp_port_to_odp_port(ntohs(opo->in_port)), &flow); error = xlate_actions((const union ofp_action *) opo->actions, n_actions, &flow, p, &payload, &actions, NULL, NULL, NULL); if (error) { @@ -2496,7 +2504,8 @@ handle_table_stats_request(struct ofproto *p, struct ofconn *ofconn, memset(ots, 0, sizeof *ots); ots->table_id = TABLEID_CLASSIFIER; strcpy(ots->name, "classifier"); - ots->wildcards = htonl(OFPFW_ALL); + ots->wildcards = p->tun_id_from_cookie ? htonl(OVSFW_ALL) + : htonl(OFPFW_ALL); ots->max_entries = htonl(65536); ots->active_count = htonl(n_wild); ots->lookup_count = htonll(0); /* XXX */ @@ -2654,7 +2663,8 @@ flow_stats_cb(struct cls_rule *rule_, void *cbdata_) ofs->length = htons(len); ofs->table_id = rule->cr.wc.wildcards ? TABLEID_CLASSIFIER : TABLEID_HASH; ofs->pad = 0; - flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &ofs->match); + flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, + cbdata->ofproto->tun_id_from_cookie, &ofs->match); ofs->duration_sec = htonl(sec); ofs->duration_nsec = htonl(msec * 1000000); ofs->cookie = rule->flow_cookie; @@ -2695,7 +2705,7 @@ handle_flow_stats_request(struct ofproto *p, struct ofconn *ofconn, cbdata.ofconn = ofconn; cbdata.out_port = fsr->out_port; cbdata.msg = start_stats_reply(osr, 1024); - cls_rule_from_match(&target, &fsr->match, 0); + cls_rule_from_match(&fsr->match, 0, false, 0, &target); classifier_for_each_match(&p->cls, &target, table_id_to_include(fsr->table_id), flow_stats_cb, &cbdata); @@ -2724,7 +2734,8 @@ flow_stats_ds_cb(struct cls_rule *rule_, void *cbdata_) } query_stats(cbdata->ofproto, rule, &packet_count, &byte_count); - flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &match); + flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, + cbdata->ofproto->tun_id_from_cookie, &match); ds_put_format(results, "duration=%llds, ", (time_msec() - rule->created) / 1000); @@ -2746,12 +2757,12 @@ ofproto_get_all_flows(struct ofproto *p, struct ds *results) struct flow_stats_ds_cbdata cbdata; memset(&match, 0, sizeof match); - match.wildcards = htonl(OFPFW_ALL); + match.wildcards = htonl(OVSFW_ALL); cbdata.ofproto = p; cbdata.results = results; - cls_rule_from_match(&target, &match, 0); + cls_rule_from_match(&match, 0, false, 0, &target); classifier_for_each_match(&p->cls, &target, CLS_INC_ALL, flow_stats_ds_cb, &cbdata); } @@ -2804,7 +2815,7 @@ handle_aggregate_stats_request(struct ofproto *p, struct ofconn *ofconn, cbdata.packet_count = 0; cbdata.byte_count = 0; cbdata.n_flows = 0; - cls_rule_from_match(&target, &asr->match, 0); + cls_rule_from_match(&asr->match, 0, false, 0, &target); classifier_for_each_match(&p->cls, &target, table_id_to_include(asr->table_id), aggregate_stats_cb, &cbdata); @@ -2912,7 +2923,8 @@ add_flow(struct ofproto *p, struct ofconn *ofconn, flow_t flow; uint32_t wildcards; - flow_from_match(&flow, &wildcards, &ofm->match); + flow_from_match(&ofm->match, p->tun_id_from_cookie, ofm->cookie, + &flow, &wildcards); if (classifier_rule_overlaps(&p->cls, &flow, wildcards, ntohs(ofm->priority))) { return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_OVERLAP); @@ -2923,7 +2935,8 @@ add_flow(struct ofproto *p, struct ofconn *ofconn, n_actions, ntohs(ofm->idle_timeout), ntohs(ofm->hard_timeout), ofm->cookie, ofm->flags & htons(OFPFF_SEND_FLOW_REM)); - cls_rule_from_match(&rule->cr, &ofm->match, ntohs(ofm->priority)); + cls_rule_from_match(&ofm->match, ntohs(ofm->priority), + p->tun_id_from_cookie, ofm->cookie, &rule->cr); error = 0; if (ofm->buffer_id != htonl(UINT32_MAX)) { @@ -2945,7 +2958,8 @@ find_flow_strict(struct ofproto *p, const struct ofp_flow_mod *ofm) uint32_t wildcards; flow_t flow; - flow_from_match(&flow, &wildcards, &ofm->match); + flow_from_match(&ofm->match, p->tun_id_from_cookie, ofm->cookie, + &flow, &wildcards); return rule_from_cls_rule(classifier_find_rule_exactly( &p->cls, &flow, wildcards, ntohs(ofm->priority))); @@ -2970,7 +2984,7 @@ send_buffered_packet(struct ofproto *ofproto, struct ofconn *ofconn, return error; } - flow_extract(packet, in_port, &flow); + flow_extract(packet, 0, in_port, &flow); rule_execute(ofproto, rule, packet, &flow); ofpbuf_delete(packet); @@ -3007,7 +3021,8 @@ modify_flows_loose(struct ofproto *p, struct ofconn *ofconn, cbdata.n_actions = n_actions; cbdata.match = NULL; - cls_rule_from_match(&target, &ofm->match, 0); + cls_rule_from_match(&ofm->match, 0, p->tun_id_from_cookie, ofm->cookie, + &target); classifier_for_each_match(&p->cls, &target, CLS_INC_ALL, modify_flows_cb, &cbdata); @@ -3108,7 +3123,8 @@ delete_flows_loose(struct ofproto *p, const struct ofp_flow_mod *ofm) cbdata.ofproto = p; cbdata.out_port = ofm->out_port; - cls_rule_from_match(&target, &ofm->match, 0); + cls_rule_from_match(&ofm->match, 0, p->tun_id_from_cookie, ofm->cookie, + &target); classifier_for_each_match(&p->cls, &target, CLS_INC_ALL, delete_flows_cb, &cbdata); @@ -3212,6 +3228,20 @@ handle_flow_mod(struct ofproto *p, struct ofconn *ofconn, } } +static int +handle_tun_id_from_cookie(struct ofproto *p, struct nxt_tun_id_cookie *msg) +{ + int error; + + error = check_ofp_message(&msg->header, OFPT_VENDOR, sizeof *msg); + if (error) { + return error; + } + + p->tun_id_from_cookie = !!msg->set; + return 0; +} + static int handle_vendor(struct ofproto *p, struct ofconn *ofconn, void *msg) { @@ -3219,12 +3249,18 @@ handle_vendor(struct ofproto *p, struct ofconn *ofconn, void *msg) struct nicira_header *nh; if (ntohs(ovh->header.length) < sizeof(struct ofp_vendor_header)) { + VLOG_WARN_RL(&rl, "received vendor message of length %zu " + "(expected at least %zu)", + ntohs(ovh->header.length), sizeof(struct ofp_vendor_header)); return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } if (ovh->vendor != htonl(NX_VENDOR_ID)) { return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR); } if (ntohs(ovh->header.length) < sizeof(struct nicira_header)) { + VLOG_WARN_RL(&rl, "received Nicira vendor message of length %zu " + "(expected at least %zu)", + ntohs(ovh->header.length), sizeof(struct nicira_header)); return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } @@ -3233,6 +3269,9 @@ handle_vendor(struct ofproto *p, struct ofconn *ofconn, void *msg) case NXT_STATUS_REQUEST: return switch_status_handle_request(p->switch_status, ofconn->rconn, msg); + + case NXT_TUN_ID_FROM_COOKIE: + return handle_tun_id_from_cookie(p, msg); } return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE); @@ -3330,7 +3369,7 @@ handle_odp_miss_msg(struct ofproto *p, struct ofpbuf *packet) payload.data = msg + 1; payload.size = msg->length - sizeof *msg; - flow_extract(&payload, msg->port, &flow); + flow_extract(&payload, msg->arg, msg->port, &flow); /* Check with in-band control to see if this packet should be sent * to the local port regardless of the flow table. */ @@ -3470,7 +3509,8 @@ revalidate_rule(struct ofproto *p, struct rule *rule) } static struct ofpbuf * -compose_flow_removed(const struct rule *rule, long long int now, uint8_t reason) +compose_flow_removed(struct ofproto *p, const struct rule *rule, + long long int now, uint8_t reason) { struct ofp_flow_removed *ofr; struct ofpbuf *buf; @@ -3479,7 +3519,8 @@ compose_flow_removed(const struct rule *rule, long long int now, uint8_t reason) uint32_t msec = tdiff - (sec * 1000); ofr = make_openflow(sizeof *ofr, OFPT_FLOW_REMOVED, &buf); - flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &ofr->match); + flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, p->tun_id_from_cookie, + &ofr->match); ofr->cookie = rule->flow_cookie; ofr->priority = htons(rule->cr.priority); ofr->reason = reason; @@ -3524,7 +3565,7 @@ send_flow_removed(struct ofproto *p, struct rule *rule, if (prev) { queue_tx(ofpbuf_clone(buf), prev, prev->reply_counter); } else { - buf = compose_flow_removed(rule, now, reason); + buf = compose_flow_removed(p, rule, now, reason); } prev = ofconn; } diff --git a/tests/test-classifier.c b/tests/test-classifier.c index 563690dd..c831559b 100644 --- a/tests/test-classifier.c +++ b/tests/test-classifier.c @@ -238,6 +238,7 @@ static uint32_t nw_src_values[] = { T_HTONL(0xc0a80001), T_HTONL(0xc0a04455) }; static uint32_t nw_dst_values[] = { T_HTONL(0xc0a80002), T_HTONL(0xc0a04455) }; +static uint32_t tun_id_values[] = { 0, 0xffff0000 }; static uint16_t in_port_values[] = { T_HTONS(1), T_HTONS(OFPP_LOCAL) }; static uint16_t dl_vlan_values[] = { T_HTONS(101), T_HTONS(0) }; static uint8_t dl_vlan_pcp_values[] = { 7, 0 }; @@ -257,6 +258,9 @@ static void *values[CLS_N_FIELDS][2]; static void init_values(void) { + values[CLS_F_IDX_TUN_ID][0] = &tun_id_values[0]; + values[CLS_F_IDX_TUN_ID][1] = &tun_id_values[1]; + values[CLS_F_IDX_IN_PORT][0] = &in_port_values[0]; values[CLS_F_IDX_IN_PORT][1] = &in_port_values[1]; @@ -296,6 +300,7 @@ init_values(void) #define N_NW_SRC_VALUES ARRAY_SIZE(nw_src_values) #define N_NW_DST_VALUES ARRAY_SIZE(nw_dst_values) +#define N_TUN_ID_VALUES ARRAY_SIZE(tun_id_values) #define N_IN_PORT_VALUES ARRAY_SIZE(in_port_values) #define N_DL_VLAN_VALUES ARRAY_SIZE(dl_vlan_values) #define N_DL_VLAN_PCP_VALUES ARRAY_SIZE(dl_vlan_pcp_values) @@ -309,6 +314,7 @@ init_values(void) #define N_FLOW_VALUES (N_NW_SRC_VALUES * \ N_NW_DST_VALUES * \ + N_TUN_ID_VALUES * \ N_IN_PORT_VALUES * \ N_DL_VLAN_VALUES * \ N_DL_VLAN_PCP_VALUES * \ @@ -360,6 +366,7 @@ compare_classifiers(struct classifier *cls, struct tcls *tcls) x = i; flow.nw_src = nw_src_values[get_value(&x, N_NW_SRC_VALUES)]; flow.nw_dst = nw_dst_values[get_value(&x, N_NW_DST_VALUES)]; + flow.tun_id = tun_id_values[get_value(&x, N_TUN_ID_VALUES)]; flow.in_port = in_port_values[get_value(&x, N_IN_PORT_VALUES)]; flow.dl_vlan = dl_vlan_values[get_value(&x, N_DL_VLAN_VALUES)]; flow.dl_vlan_pcp = dl_vlan_pcp_values[get_value(&x, @@ -462,8 +469,8 @@ make_rule(int wc_fields, unsigned int priority, int value_pat) } rule = xzalloc(sizeof *rule); - cls_rule_from_flow(&rule->cls_rule, &flow, wildcards, - !wildcards ? UINT_MAX : priority); + cls_rule_from_flow(&flow, wildcards, !wildcards ? UINT_MAX : priority, + &rule->cls_rule); return rule; } diff --git a/tests/test-flows.c b/tests/test-flows.c index 451ca1ad..424dd7b0 100644 --- a/tests/test-flows.c +++ b/tests/test-flows.c @@ -67,8 +67,8 @@ main(int argc OVS_UNUSED, char *argv[]) ovs_fatal(retval, "error reading pcap file"); } - flow_extract(packet, 1, &flow); - flow_to_match(&flow, 0, &extracted_match); + flow_extract(packet, 0, 1, &flow); + flow_to_match(&flow, 0, false, &extracted_match); if (memcmp(&expected_match, &extracted_match, sizeof expected_match)) { char *exp_s = ofp_match_to_string(&expected_match, 2); diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index 948df51d..04b0a989 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -391,14 +391,22 @@ Sets the IP ToS/DSCP field to \fItos\fR. Valid values are between 0 and 255, inclusive. Note that the two lower reserved bits are never modified. . +.RE +.IP +The following actions are Nicira vendor extensions that, as of this writing, are +only known to be implemented by Open vSwitch: +. +.RS +. .IP \fBresubmit\fB:\fIport\fR Re-searches the OpenFlow flow table with the \fBin_port\fR field replaced by \fIport\fR and executes the actions found, if any, in addition to any other actions in this flow entry. Recursive \fBresubmit\fR actions are ignored. -.IP -This action is a Nicira vendor extension that, as of this writing, is -only known to be implemented by Open vSwitch. +. +.IP \fBset_tunnel\fB:\fIid\fR +If outputting to a port that encapsulates the packet in a tunnel and supports +an identifier (such as GRE), sets the identifier to \fBid\fR. . .RE . diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 204e9582..d9ee607b 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -647,6 +647,12 @@ str_to_action(char *str, struct ofpbuf *b) nar->vendor = htonl(NX_VENDOR_ID); nar->subtype = htons(NXAST_RESUBMIT); nar->in_port = htons(str_to_u32(arg)); + } else if (!strcasecmp(act, "set_tunnel")) { + struct nx_action_set_tunnel *nast; + nast = put_action(b, sizeof *nast, OFPAT_VENDOR); + nast->vendor = htonl(NX_VENDOR_ID); + nast->subtype = htons(NXAST_SET_TUNNEL); + nast->tun_id = htonl(str_to_u32(arg)); } else if (!strcasecmp(act, "output")) { put_output_action(b, str_to_u32(arg)); } else if (!strcasecmp(act, "drop")) { @@ -717,7 +723,7 @@ static bool parse_field(const char *name, const struct field **f_out) { #define F_OFS(MEMBER) offsetof(struct ofp_match, MEMBER) - static const struct field fields[] = { + static const struct field fields[] = { { "in_port", OFPFW_IN_PORT, F_U16, F_OFS(in_port), 0 }, { "dl_vlan", OFPFW_DL_VLAN, F_U16, F_OFS(dl_vlan), 0 }, { "dl_vlan_pcp", OFPFW_DL_VLAN_PCP, F_U8, F_OFS(dl_vlan_pcp), 0 }, @@ -825,6 +831,8 @@ str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions, *hard_timeout = atoi(value); } else if (cookie && !strcmp(name, "cookie")) { *cookie = str_to_u64(value); + } else if (!strcmp(name, "tun_id_wild")) { + wildcards |= NXFW_TUN_ID; } else if (parse_field(name, &f)) { void *data = (char *) match + f->offset; if (!strcmp(value, "*") || !strcmp(value, "ANY")) { @@ -1033,6 +1041,24 @@ static void do_del_flows(int argc, char *argv[]) vconn_close(vconn); } +static void +do_tun_cookie(int argc OVS_UNUSED, char *argv[]) +{ + struct nxt_tun_id_cookie *tun_id_cookie; + struct ofpbuf *buffer; + struct vconn *vconn; + + tun_id_cookie = make_openflow(sizeof *tun_id_cookie, OFPT_VENDOR, &buffer); + + tun_id_cookie->vendor = htonl(NX_VENDOR_ID); + tun_id_cookie->subtype = htonl(NXT_TUN_ID_FROM_COOKIE); + tun_id_cookie->set = !strcmp(argv[2], "true"); + + open_vconn(argv[1], &vconn); + send_openflow_buffer(vconn, buffer); + vconn_close(vconn); +} + static void do_monitor(int argc OVS_UNUSED, char *argv[]) { @@ -1274,6 +1300,7 @@ static const struct command all_commands[] = { { "add-flows", 2, 2, do_add_flows }, { "mod-flows", 2, 2, do_mod_flows }, { "del-flows", 1, 2, do_del_flows }, + { "tun-cookie", 2, 2, do_tun_cookie }, { "dump-ports", 1, 2, do_dump_ports }, { "mod-port", 3, 3, do_mod_port }, { "probe", 1, 1, do_probe }, diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 2d605256..04755b7b 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -1590,8 +1590,7 @@ bridge_reconfigure_controller(const struct ovsrec_open_vswitch *ovs_cfg, action.output.len = htons(sizeof action); action.output.port = htons(OFPP_NORMAL); memset(&flow, 0, sizeof flow); - ofproto_add_flow(br->ofproto, &flow, OFPFW_ALL, 0, - &action, 1, 0); + ofproto_add_flow(br->ofproto, &flow, OVSFW_ALL, 0, &action, 1, 0); ofproto_set_in_band(br->ofproto, false); ofproto_set_max_backoff(br->ofproto, 1); @@ -2779,7 +2778,7 @@ bond_send_learning_packets(struct port *port) n_packets++; compose_benign_packet(&packet, "Open vSwitch Bond Failover", 0xf177, e->mac); - flow_extract(&packet, ODPP_NONE, &flow); + flow_extract(&packet, 0, ODPP_NONE, &flow); retval = ofproto_send_packet(br->ofproto, &flow, actions, a - actions, &packet); if (retval) {