#include "netlink.h"
#include "nx-match.h"
#include "odp-util.h"
+#include "odp-execute.h"
#include "ofp-util.h"
#include "ofpbuf.h"
#include "ofp-actions.h"
int vid;
};
-static uint32_t vsp_realdev_to_vlandev(const struct ofproto_dpif *,
- uint32_t realdev, ovs_be16 vlan_tci);
+static uint16_t vsp_realdev_to_vlandev(const struct ofproto_dpif *,
+ uint16_t realdev_ofp_port,
+ ovs_be16 vlan_tci);
static bool vsp_adjust_flow(const struct ofproto_dpif *, struct flow *);
static void vsp_remove(struct ofport_dpif *);
static void vsp_add(struct ofport_dpif *, uint16_t realdev_ofp_port, int vid);
/* Special OpenFlow rules. */
struct rule_dpif *miss_rule; /* Sends flow table misses to controller. */
struct rule_dpif *no_packet_in_rule; /* Drops flow table misses. */
+ struct rule_dpif *drop_frags_rule; /* Used in OFPC_FRAG_DROP mode. */
/* Bridging. */
struct netflow *netflow;
ofpbuf_clear(&ofpacts);
error = add_internal_flow(ofproto, id++, &ofpacts,
&ofproto->no_packet_in_rule);
+ if (error) {
+ return error;
+ }
+
+ error = add_internal_flow(ofproto, id++, &ofpacts,
+ &ofproto->drop_frags_rule);
return error;
}
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
struct dpif_dp_stats s;
- uint64_t n_miss, n_no_pkt_in, n_bytes;
+ uint64_t n_miss, n_no_pkt_in, n_bytes, n_dropped_frags;
uint64_t n_lookup;
strcpy(ots->name, "classifier");
dpif_get_dp_stats(ofproto->backer->dpif, &s);
rule_get_stats(&ofproto->miss_rule->up, &n_miss, &n_bytes);
rule_get_stats(&ofproto->no_packet_in_rule->up, &n_no_pkt_in, &n_bytes);
+ rule_get_stats(&ofproto->drop_frags_rule->up, &n_dropped_frags, &n_bytes);
- n_lookup = s.n_hit + s.n_missed;
+ n_lookup = s.n_hit + s.n_missed - n_dropped_frags;
ots->lookup_count = htonll(n_lookup);
ots->matched_count = htonll(n_lookup - n_miss - n_no_pkt_in);
}
if (port->bundle && port->bundle->bond) {
bond_slave_set_netdev(port->bundle->bond, port, port->up.netdev);
}
+
+ if (port->cfm) {
+ cfm_set_netdev(port->cfm, port->up.netdev);
+ }
}
static void
* flow keys with fitness ODP_FIT_TO_LITTLE. This breaks a fundamental
* assumption used throughout the facet and subfacet handling code.
* Since we have to handle these misses in userspace anyway, we simply
- * skip facet creation, avoiding the problem alltogether. */
+ * skip facet creation, avoiding the problem altogether. */
if (miss->key_fitness == ODP_FIT_TOO_LITTLE
|| !flow_miss_should_make_facet(ofproto, miss, hash)) {
handle_flow_miss_without_facet(miss, ops, n_ops);
{
struct cls_rule *cls_rule;
struct classifier *cls;
+ bool frag;
if (table_id >= N_TABLES) {
return NULL;
}
cls = &ofproto->up.tables[table_id].cls;
- if (flow->nw_frag & FLOW_NW_FRAG_ANY
- && ofproto->up.frag_handling == OFPC_FRAG_NORMAL) {
- /* For OFPC_NORMAL frag_handling, we must pretend that transport ports
- * are unavailable. */
+ frag = (flow->nw_frag & FLOW_NW_FRAG_ANY) != 0;
+ if (frag && ofproto->up.frag_handling == OFPC_FRAG_NORMAL) {
+ /* We must pretend that transport ports are unavailable. */
struct flow ofpc_normal_flow = *flow;
ofpc_normal_flow.tp_src = htons(0);
ofpc_normal_flow.tp_dst = htons(0);
cls_rule = classifier_lookup(cls, &ofpc_normal_flow);
+ } else if (frag && ofproto->up.frag_handling == OFPC_FRAG_DROP) {
+ cls_rule = &ofproto->drop_frags_rule->up.cr;
} else {
cls_rule = classifier_lookup(cls, flow);
}
&ctx->xout->odp_actions);
ctx->xin->flow.tunnel = flow_tnl; /* Restore tunnel metadata */
} else {
+ uint16_t vlandev_port;
odp_port = ofport->odp_port;
- out_port = vsp_realdev_to_vlandev(ctx->ofproto, odp_port,
- ctx->xin->flow.vlan_tci);
- if (out_port != odp_port) {
+ vlandev_port = vsp_realdev_to_vlandev(ctx->ofproto, ofp_port,
+ ctx->xin->flow.vlan_tci);
+ if (vlandev_port == ofp_port) {
+ out_port = odp_port;
+ } else {
+ out_port = ofp_port_to_odp_port(ctx->ofproto, vlandev_port);
ctx->xin->flow.vlan_tci = htons(0);
}
ctx->xin->flow.skb_mark &= ~IPSEC_MARK;
{
struct ofputil_packet_in pin;
struct ofpbuf *packet;
+ struct flow key;
ovs_assert(!ctx->xout->slow || ctx->xout->slow == SLOW_CONTROLLER);
ctx->xout->slow = SLOW_CONTROLLER;
packet = ofpbuf_clone(ctx->xin->packet);
- if (packet->l2 && packet->l3) {
- struct eth_header *eh;
- uint16_t mpls_depth;
-
- eth_pop_vlan(packet);
- eh = packet->l2;
-
- memcpy(eh->eth_src, ctx->xin->flow.dl_src, sizeof eh->eth_src);
- memcpy(eh->eth_dst, ctx->xin->flow.dl_dst, sizeof eh->eth_dst);
-
- if (ctx->xin->flow.vlan_tci & htons(VLAN_CFI)) {
- eth_push_vlan(packet, ctx->xin->flow.vlan_tci);
- }
-
- mpls_depth = eth_mpls_depth(packet);
+ key.skb_priority = 0;
+ key.skb_mark = 0;
+ memset(&key.tunnel, 0, sizeof key.tunnel);
- if (mpls_depth < ctx->xin->flow.mpls_depth) {
- push_mpls(packet, ctx->xin->flow.dl_type, ctx->xin->flow.mpls_lse);
- } else if (mpls_depth > ctx->xin->flow.mpls_depth) {
- pop_mpls(packet, ctx->xin->flow.dl_type);
- } else if (mpls_depth) {
- set_mpls_lse(packet, ctx->xin->flow.mpls_lse);
- }
+ commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
+ &ctx->xout->odp_actions);
- if (packet->l4) {
- if (ctx->xin->flow.dl_type == htons(ETH_TYPE_IP)) {
- packet_set_ipv4(packet, ctx->xin->flow.nw_src,
- ctx->xin->flow.nw_dst, ctx->xin->flow.nw_tos,
- ctx->xin->flow.nw_ttl);
- }
-
- if (packet->l7) {
- if (ctx->xin->flow.nw_proto == IPPROTO_TCP) {
- packet_set_tcp_port(packet, ctx->xin->flow.tp_src,
- ctx->xin->flow.tp_dst);
- } else if (ctx->xin->flow.nw_proto == IPPROTO_UDP) {
- packet_set_udp_port(packet, ctx->xin->flow.tp_src,
- ctx->xin->flow.tp_dst);
- }
- }
- }
- }
+ odp_execute_actions(NULL, packet, &key, ctx->xout->odp_actions.data,
+ ctx->xout->odp_actions.size, NULL, NULL);
pin.packet = packet->data;
pin.packet_len = packet->size;
} else if (rule == ofproto->no_packet_in_rule) {
ds_put_cstr(ds, "\nNo match, packets dropped because "
"OFPPC_NO_PACKET_IN is set on in_port.\n");
+ } else if (rule == ofproto->drop_frags_rule) {
+ ds_put_cstr(ds, "\nPackets dropped because they are IP fragments "
+ "and the fragment handling mode is \"drop\".\n");
}
if (rule) {
return hash_2words(realdev_ofp_port, vid);
}
-/* Returns the ODP port number of the Linux VLAN device that corresponds to
- * 'vlan_tci' on the network device with port number 'realdev_odp_port' in
- * 'ofproto'. For example, given 'realdev_odp_port' of eth0 and 'vlan_tci' 9,
- * it would return the port number of eth0.9.
+/* Returns the OFP port number of the Linux VLAN device that corresponds to
+ * 'vlan_tci' on the network device with port number 'realdev_ofp_port' in
+ * 'struct ofport_dpif'. For example, given 'realdev_ofp_port' of eth0 and
+ * 'vlan_tci' 9, it would return the port number of eth0.9.
*
- * Unless VLAN splinters are enabled for port 'realdev_odp_port', this
- * function just returns its 'realdev_odp_port' argument. */
-static uint32_t
+ * Unless VLAN splinters are enabled for port 'realdev_ofp_port', this
+ * function just returns its 'realdev_ofp_port' argument. */
+static uint16_t
vsp_realdev_to_vlandev(const struct ofproto_dpif *ofproto,
- uint32_t realdev_odp_port, ovs_be16 vlan_tci)
+ uint16_t realdev_ofp_port, ovs_be16 vlan_tci)
{
if (!hmap_is_empty(&ofproto->realdev_vid_map)) {
- uint16_t realdev_ofp_port;
int vid = vlan_tci_to_vid(vlan_tci);
const struct vlan_splinter *vsp;
- realdev_ofp_port = odp_port_to_ofp_port(ofproto, realdev_odp_port);
HMAP_FOR_EACH_WITH_HASH (vsp, realdev_vid_node,
hash_realdev_vid(realdev_ofp_port, vid),
&ofproto->realdev_vid_map) {
if (vsp->realdev_ofp_port == realdev_ofp_port
&& vsp->vid == vid) {
- return ofp_port_to_odp_port(ofproto, vsp->vlandev_ofp_port);
+ return vsp->vlandev_ofp_port;
}
}
}
- return realdev_odp_port;
+ return realdev_ofp_port;
}
static struct vlan_splinter *