[ovs-discuss] [PATCH 8/9] PROC: L3 in-band
Justin Pettit
jpettit at nicira.com
Wed Jul 29 22:21:08 UTC 2009
---
lib/dpif.c | 22 +++++
lib/dpif.h | 2 +
lib/netdev.c | 40 --------
lib/netdev.h | 3 -
secchan/in-band.c | 267 ++++++++++++++++++++++++++++++-----------------------
secchan/in-band.h | 7 +-
secchan/ofproto.c | 27 ++++-
7 files changed, 203 insertions(+), 165 deletions(-)
diff --git a/lib/dpif.c b/lib/dpif.c
index 21f1173..323a7cf 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -322,6 +322,28 @@ dpif_port_query_by_name(const struct dpif *dpif, const char *devname,
}
}
+/* Looks up port number 'port_no' in 'dpif'. On success, returns 0 and copies
+ * the port's name into the 'name_size' bytes in 'name', ensuring that the
+ * result is null-terminated. On failure, returns a positive errno value and
+ * makes 'name' the empty string. */
+int
+dpif_port_get_name(struct dpif *dpif, uint16_t port_no,
+ char *name, size_t name_size)
+{
+ struct odp_port port;
+ int error;
+
+ assert(name_size > 0);
+
+ error = dpif_port_query_by_number(dpif, port_no, &port);
+ if (!error) {
+ ovs_strlcpy(name, port.devname, name_size);
+ } else {
+ *name = '\0';
+ }
+ return error;
+}
+
int
dpif_port_list(const struct dpif *dpif,
struct odp_port **ports, size_t *n_ports)
diff --git a/lib/dpif.h b/lib/dpif.h
index d81cf63..a098580 100644
--- a/lib/dpif.h
+++ b/lib/dpif.h
@@ -59,6 +59,8 @@ int dpif_port_query_by_number(const struct dpif *, uint16_t port_no,
struct odp_port *);
int dpif_port_query_by_name(const struct dpif *, const char *devname,
struct odp_port *);
+int dpif_port_get_name(struct dpif *dpif, uint16_t port_no,
+ char *name, size_t name_size);
int dpif_port_list(const struct dpif *, struct odp_port **, size_t *n_ports);
int dpif_port_group_set(struct dpif *, uint16_t group,
diff --git a/lib/netdev.c b/lib/netdev.c
index 912f88f..ca1a63d 100644
--- a/lib/netdev.c
+++ b/lib/netdev.c
@@ -987,46 +987,6 @@ netdev_turn_flags_off(struct netdev *netdev, enum netdev_flags flags,
return do_update_flags(netdev, flags, 0, permanent);
}
-/* Looks up the ARP table entry for 'ip' on 'netdev'. If one exists and can be
- * successfully retrieved, it stores the corresponding MAC address in 'mac' and
- * returns 0. Otherwise, it returns a positive errno value; in particular,
- * ENXIO indicates that there is not ARP table entry for 'ip' on 'netdev'. */
-int
-netdev_nodev_arp_lookup(const char *netdev_name, uint32_t ip,
- uint8_t mac[ETH_ADDR_LEN])
-{
- struct arpreq r;
- struct sockaddr_in *pa;
- int retval;
-
- init_netdev();
-
- memset(&r, 0, sizeof r);
- pa = (struct sockaddr_in *) &r.arp_pa;
- pa->sin_family = AF_INET;
- pa->sin_addr.s_addr = ip;
- pa->sin_port = 0;
- r.arp_ha.sa_family = ARPHRD_ETHER;
- r.arp_flags = 0;
- strncpy(r.arp_dev, netdev_name, sizeof r.arp_dev);
- COVERAGE_INC(netdev_arp_lookup);
- retval = ioctl(af_inet_sock, SIOCGARP, &r) < 0 ? errno : 0;
- if (!retval) {
- memcpy(mac, r.arp_ha.sa_data, ETH_ADDR_LEN);
- } else if (retval != ENXIO) {
- VLOG_WARN_RL(&rl, "%s: could not look up ARP entry for "IP_FMT": %s",
- netdev_name, IP_ARGS(&ip), strerror(retval));
- }
- return retval;
-}
-
-int
-netdev_arp_lookup(const struct netdev *netdev, uint32_t ip,
- uint8_t mac[ETH_ADDR_LEN])
-{
- return netdev_nodev_arp_lookup(netdev->name, ip, mac);
-}
-
static int
get_stats_via_netlink(int ifindex, struct netdev_stats *stats)
{
diff --git a/lib/netdev.h b/lib/netdev.h
index 9a55619..e876327 100644
--- a/lib/netdev.h
+++ b/lib/netdev.h
@@ -99,7 +99,6 @@ int netdev_get_flags(const struct netdev *, enum netdev_flags *);
int netdev_set_flags(struct netdev *, enum netdev_flags, bool permanent);
int netdev_turn_flags_on(struct netdev *, enum netdev_flags, bool permanent);
int netdev_turn_flags_off(struct netdev *, enum netdev_flags, bool permanent);
-int netdev_arp_lookup(const struct netdev *, uint32_t ip, uint8_t mac[6]);
int netdev_get_carrier(const struct netdev *, bool *carrier);
int netdev_get_stats(const struct netdev *, struct netdev_stats *);
int netdev_set_policing(struct netdev *, uint32_t kbits_rate,
@@ -114,8 +113,6 @@ int netdev_nodev_set_etheraddr(const char *name, const uint8_t mac[6]);
int netdev_nodev_get_etheraddr(const char *netdev_name, uint8_t mac[6]);
int netdev_nodev_set_policing(const char *netdev_name, uint32_t kbits_rate,
uint32_t kbits_burst);
-int netdev_nodev_arp_lookup(const char *netdev_name, uint32_t ip,
- uint8_t mac[6]);
int netdev_nodev_get_carrier(const char *netdev_name, bool *carrier);
int netdev_get_vlan_vid(const char *netdev_name, int *vlan_vid);
diff --git a/secchan/in-band.c b/secchan/in-band.c
index 6026efd..881e1fd 100644
--- a/secchan/in-band.c
+++ b/secchan/in-band.c
@@ -22,6 +22,8 @@
#include <net/if.h>
#include <string.h>
#include <stdlib.h>
+#include "dhcp.h"
+#include "dpif.h"
#include "flow.h"
#include "mac-learning.h"
#include "netdev.h"
@@ -30,6 +32,7 @@
#include "ofproto.h"
#include "ofpbuf.h"
#include "openflow/openflow.h"
+#include "openvswitch/datapath-protocol.h"
#include "packets.h"
#include "poll-loop.h"
#include "rconn.h"
@@ -43,15 +46,12 @@
#define IB_BASE_PRIORITY 18181800
enum {
- IBR_FROM_LOCAL_PORT, /* Sent by the local port. */
- IBR_OFP_TO_LOCAL, /* Sent to secure channel on local port. */
- IBR_ARP_FROM_LOCAL, /* ARP from the local port. */
- IBR_ARP_TO_LOCAL, /* ARP to the local port. */
- IBR_ARP_FROM_CTL, /* ARP from the controller. */
- IBR_TO_CTL_OFP_SRC, /* To controller, OpenFlow source port. */
- IBR_TO_CTL_OFP_DST, /* To controller, OpenFlow dest port. */
- IBR_FROM_CTL_OFP_SRC, /* From controller, OpenFlow source port. */
- IBR_FROM_CTL_OFP_DST, /* From controller, OpenFlow dest port. */
+ IBR_FROM_LOCAL_DHCP, /* From local port, DHCP. */
+ IBR_TO_LOCAL_DHCP, /* To local port, DHCP. */
+ IBR_TO_CTL_ARP, /* To controller, ARP. */
+ IBR_FROM_CTL_ARP, /* From controller, ARP. */
+ IBR_TO_CTL_OFP, /* To controller, OpenFlow port. */
+ IBR_FROM_CTL_OFP, /* From controller, OpenFlow port. */
#if OFP_TCP_PORT != OFP_SSL_PORT
#error Need to support separate TCP and SSL flows.
#endif
@@ -70,17 +70,13 @@ struct in_band {
struct rconn *controller;
struct status_category *ss_cat;
- /* Keeping track of controller's MAC address. */
- uint32_t ip; /* Current IP, 0 if unknown. */
- uint32_t last_ip; /* Last known IP, 0 if never known. */
- uint8_t mac[ETH_ADDR_LEN]; /* Current MAC, 0 if unknown. */
- uint8_t last_mac[ETH_ADDR_LEN]; /* Last known MAC, 0 if never known */
- char *dev_name;
- time_t next_refresh; /* Next time to refresh MAC address. */
-
/* Keeping track of the local port's MAC address. */
- uint8_t local_mac[ETH_ADDR_LEN]; /* Current MAC. */
- time_t next_local_refresh; /* Next time to refresh MAC address. */
+ uint8_t local_mac[ETH_ADDR_LEN]; /* Current MAC. */
+ char local_name[IF_NAMESIZE]; /* Local device name. */
+ time_t next_local_refresh; /* Next time to refresh MAC address. */
+
+ uint32_t controller_ip; /* Current IP, 0 if unknown. */
+ time_t next_refresh;
/* Rules that we set up. */
struct ib_rule rules[N_IB_RULES];
@@ -152,7 +148,7 @@ get_local_mac(struct in_band *ib)
time_t now = time_now();
if (now >= ib->next_local_refresh) {
uint8_t ea[ETH_ADDR_LEN];
- if (ib->dev_name && (!netdev_nodev_get_etheraddr(ib->dev_name, ea))) {
+ if (!netdev_nodev_get_etheraddr(ib->local_name, ea)) {
memcpy(ib->local_mac, ea, ETH_ADDR_LEN);
}
ib->next_local_refresh = now + 1;
@@ -165,19 +161,12 @@ in_band_status_cb(struct status_reply *sr, void *in_band_)
{
struct in_band *in_band = in_band_;
const uint8_t *local_mac;
- const uint8_t *controller_mac;
local_mac = get_local_mac(in_band);
if (local_mac) {
status_reply_put(sr, "local-mac="ETH_ADDR_FMT,
ETH_ADDR_ARGS(local_mac));
}
-
- controller_mac = get_controller_mac(in_band);
- if (controller_mac) {
- status_reply_put(sr, "controller-mac="ETH_ADDR_FMT,
- ETH_ADDR_ARGS(controller_mac));
- }
}
static void
@@ -218,103 +207,143 @@ setup_flow(struct in_band *in_band, int rule_idx, const flow_t *flow,
}
}
+/* Returns true if 'packet' should be sent to the local port regardless
+ * of the flow table. */
+bool
+in_band_msg_in_hook(struct in_band *in_band, const flow_t *flow,
+ const struct ofpbuf *packet)
+{
+ if (!in_band) {
+ return false;
+ }
+
+ if ((flow->nw_proto == IP_TYPE_UDP)
+ && (flow->tp_src == htons(DHCP_SERVER_PORT))
+ && (flow->tp_dst == htons(DHCP_CLIENT_PORT))
+ && (packet->size >= DHCP_HEADER_LEN)) {
+ struct dhcp_header *dhcp = packet->l7;
+ const uint8_t *local_mac;
+
+ local_mac = get_local_mac(in_band);
+ if (!memcmp(dhcp->chaddr, local_mac, ETH_ADDR_LEN)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Returns true if the rule that would match 'flow' with 'actions' is
+ * allowed to be setup in the datapath. */
+bool
+in_band_rule_check(struct in_band *in_band, const flow_t *flow,
+ const struct odp_actions *actions)
+{
+ if (!in_band) {
+ return true;
+ }
+
+ /* Don't allow flows that would prevent DHCP replies from being seen
+ * by the local port. */
+ if ((flow->nw_proto == IP_TYPE_UDP)
+ && (flow->tp_src == htons(DHCP_SERVER_PORT))
+ && (flow->tp_dst == htons(DHCP_CLIENT_PORT))) {
+ int i;
+
+ for (i=0; i<actions->n_actions; i++) {
+ if (actions->actions[i].output.type == ODPAT_OUTPUT
+ && actions->actions[i].output.port == ODPP_LOCAL) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ return true;
+}
+
void
in_band_run(struct in_band *in_band)
{
- const uint8_t *controller_mac;
- const uint8_t *local_mac;
+ time_t now = time_now();
+ uint32_t controller_ip;
flow_t flow;
- if (time_now() < MIN(in_band->next_refresh, in_band->next_local_refresh)) {
+ if (now < MIN(in_band->next_refresh, in_band->next_local_refresh)) {
return;
}
-
- /* NOTE: A router may sit between the switch and controller, so
- * we could not tie this to the controller's MAC address. If the
- * switch and controller are on different subnets, we should be
- * using the router's MAC address in the 'controller_mac'. */
- controller_mac = get_controller_mac(in_band);
- local_mac = get_local_mac(in_band);
- /* Switch traffic sent by the local port. */
- memset(&flow, 0, sizeof flow);
- flow.in_port = ODPP_LOCAL;
- setup_flow(in_band, IBR_FROM_LOCAL_PORT, &flow, OFPFW_IN_PORT,
- OFPP_NORMAL);
+ controller_ip = rconn_get_remote_ip(in_band->controller);
+ in_band->next_refresh = now + (controller_ip ? 10 : 1);
- if (local_mac) {
- /* Deliver traffic sent over the secure channel to the connection's
- * interface. */
- memset(&flow, 0, sizeof flow);
- flow.dl_type = htons(ETH_TYPE_IP);
- memcpy(flow.dl_dst, local_mac, ETH_ADDR_LEN);
- flow.nw_proto = IP_TYPE_TCP;
- flow.tp_src = htons(OFP_TCP_PORT);
- setup_flow(in_band, IBR_OFP_TO_LOCAL, &flow,
- (OFPFW_DL_TYPE | OFPFW_DL_DST | OFPFW_NW_PROTO
- | OFPFW_TP_SRC), OFPP_NORMAL);
-
- /* Allow the connection's interface to be the source of ARP traffic. */
- memset(&flow, 0, sizeof flow);
- flow.dl_type = htons(ETH_TYPE_ARP);
- memcpy(flow.dl_src, local_mac, ETH_ADDR_LEN);
- setup_flow(in_band, IBR_ARP_FROM_LOCAL, &flow,
- OFPFW_DL_TYPE | OFPFW_DL_SRC, OFPP_NORMAL);
-
- /* Allow the connection's interface to receive directed ARP traffic. */
- memset(&flow, 0, sizeof flow);
- flow.dl_type = htons(ETH_TYPE_ARP);
- memcpy(flow.dl_dst, local_mac, ETH_ADDR_LEN);
- setup_flow(in_band, IBR_ARP_TO_LOCAL, &flow,
- OFPFW_DL_TYPE | OFPFW_DL_DST, OFPP_NORMAL);
- } else {
- drop_flow(in_band, IBR_OFP_TO_LOCAL);
- drop_flow(in_band, IBR_ARP_FROM_LOCAL);
- drop_flow(in_band, IBR_ARP_TO_LOCAL);
+ if (controller_ip == in_band->controller_ip) {
+ return;
+ } else if (!controller_ip) {
+ drop_flow(in_band, IBR_TO_CTL_ARP);
+ drop_flow(in_band, IBR_FROM_CTL_ARP);
+ drop_flow(in_band, IBR_TO_CTL_OFP);
+ drop_flow(in_band, IBR_FROM_CTL_OFP);
+
+ in_band->next_refresh = now + 1;
+ in_band->controller_ip = controller_ip;
+
+ return;
}
- if (controller_mac) {
- /* Switch ARP requests sent by the controller. (OFPP_NORMAL will "do
- * the right thing" regarding VLANs here.) */
- memset(&flow, 0, sizeof flow);
- flow.dl_type = htons(ETH_TYPE_ARP);
- memcpy(flow.dl_dst, eth_addr_broadcast, ETH_ADDR_LEN);
- memcpy(flow.dl_src, controller_mac, ETH_ADDR_LEN);
- setup_flow(in_band, IBR_ARP_FROM_CTL, &flow,
- OFPFW_DL_TYPE | OFPFW_DL_DST | OFPFW_DL_SRC,
- OFPP_NORMAL);
-
- /* OpenFlow traffic to or from the controller.
- *
- * (A given field's value is completely ignored if it is wildcarded,
- * which is why we can get away with using a single 'flow' in each
- * case here.) */
- memset(&flow, 0, sizeof flow);
- flow.dl_type = htons(ETH_TYPE_IP);
- memcpy(flow.dl_src, controller_mac, ETH_ADDR_LEN);
- memcpy(flow.dl_dst, controller_mac, ETH_ADDR_LEN);
- flow.nw_proto = IP_TYPE_TCP;
- flow.tp_src = htons(OFP_TCP_PORT);
- flow.tp_dst = htons(OFP_TCP_PORT);
- setup_flow(in_band, IBR_TO_CTL_OFP_SRC, &flow,
- (OFPFW_DL_TYPE | OFPFW_DL_DST | OFPFW_NW_PROTO
- | OFPFW_TP_SRC), OFPP_NORMAL);
- setup_flow(in_band, IBR_TO_CTL_OFP_DST, &flow,
- (OFPFW_DL_TYPE | OFPFW_DL_DST | OFPFW_NW_PROTO
- | OFPFW_TP_DST), OFPP_NORMAL);
- setup_flow(in_band, IBR_FROM_CTL_OFP_SRC, &flow,
- (OFPFW_DL_TYPE | OFPFW_DL_SRC | OFPFW_NW_PROTO
- | OFPFW_TP_SRC), OFPP_NORMAL);
- setup_flow(in_band, IBR_FROM_CTL_OFP_DST, &flow,
- (OFPFW_DL_TYPE | OFPFW_DL_SRC | OFPFW_NW_PROTO
- | OFPFW_TP_DST), OFPP_NORMAL);
- } else {
- drop_flow(in_band, IBR_ARP_FROM_CTL);
- drop_flow(in_band, IBR_TO_CTL_OFP_DST);
- drop_flow(in_band, IBR_TO_CTL_OFP_SRC);
- drop_flow(in_band, IBR_FROM_CTL_OFP_DST);
- drop_flow(in_band, IBR_FROM_CTL_OFP_SRC);
+ if (in_band->controller_ip) {
+ VLOG_DBG("controller IP address changed from "IP_FMT" to "IP_FMT,
+ IP_ARGS(&in_band->controller_ip),
+ IP_ARGS(&controller_ip));
}
+ in_band->controller_ip = controller_ip;
+
+ /* Allow DHCP requests to be sent from the local port. */
+ memset(&flow, 0, sizeof flow);
+ flow.in_port = ODPP_LOCAL;
+ flow.dl_type = htons(ETH_TYPE_IP);
+ flow.nw_proto = IP_TYPE_UDP;
+ flow.tp_src = htons(DHCP_CLIENT_PORT);
+ flow.tp_dst = htons(DHCP_SERVER_PORT);
+ setup_flow(in_band, IBR_FROM_LOCAL_DHCP, &flow,
+ (OFPFW_IN_PORT | OFPFW_DL_TYPE | OFPFW_NW_PROTO
+ | OFPFW_TP_SRC | OFPFW_TP_DST), OFPP_NORMAL);
+
+ /* Allow ARP requests about the controller through. */
+ memset(&flow, 0, sizeof flow);
+ flow.dl_type = htons(ETH_TYPE_ARP);
+ flow.nw_proto = ARP_OP_REQUEST;
+ flow.nw_src = controller_ip;
+ setup_flow(in_band, IBR_TO_CTL_ARP, &flow,
+ (OFPFW_DL_TYPE | OFPFW_NW_PROTO | OFPFW_NW_SRC_MASK),
+ OFPP_NORMAL);
+
+ /* Allow ARP requests from the controller through. */
+ memset(&flow, 0, sizeof flow);
+ flow.dl_type = htons(ETH_TYPE_ARP);
+ flow.nw_proto = ARP_OP_REPLY;
+ flow.nw_dst = controller_ip;
+ setup_flow(in_band, IBR_FROM_CTL_ARP, &flow,
+ (OFPFW_DL_TYPE | OFPFW_NW_PROTO | OFPFW_NW_DST_MASK),
+ OFPP_NORMAL);
+
+ /* OpenFlow traffic to or from the controller.
+ *
+ * (A given field's value is completely ignored if it is wildcarded,
+ * which is why we can get away with using a single 'flow' in each
+ * case here.) */
+ memset(&flow, 0, sizeof flow);
+ flow.dl_type = htons(ETH_TYPE_IP);
+ flow.nw_proto = IP_TYPE_TCP;
+ flow.nw_src = controller_ip;
+ flow.nw_dst = controller_ip;
+ flow.tp_src = htons(OFP_TCP_PORT);
+ flow.tp_dst = htons(OFP_TCP_PORT);
+ setup_flow(in_band, IBR_FROM_CTL_OFP, &flow,
+ (OFPFW_DL_TYPE | OFPFW_NW_PROTO | OFPFW_NW_SRC_MASK
+ | OFPFW_TP_SRC), OFPP_NORMAL);
+ setup_flow(in_band, IBR_TO_CTL_OFP, &flow,
+ (OFPFW_DL_TYPE | OFPFW_NW_PROTO | OFPFW_NW_DST_MASK
+ | OFPFW_TP_DST), OFPP_NORMAL);
}
void
@@ -340,19 +369,27 @@ in_band_flushed(struct in_band *in_band)
}
void
-in_band_create(struct ofproto *ofproto, struct switch_status *ss,
- struct rconn *controller, struct in_band **in_bandp)
+in_band_create(struct ofproto *ofproto, struct dpif *dpif,
+ struct switch_status *ss, struct rconn *controller,
+ struct in_band **in_bandp)
{
struct in_band *in_band;
+ int error;
in_band = xcalloc(1, sizeof *in_band);
+ error = dpif_port_get_name(dpif, ODPP_LOCAL, in_band->local_name,
+ sizeof in_band->local_name);
+ if (error) {
+ free(in_band);
+ return;
+ }
+
in_band->ofproto = ofproto;
in_band->controller = controller;
in_band->ss_cat = switch_status_register(ss, "in-band",
in_band_status_cb, in_band);
in_band->next_refresh = TIME_MIN;
in_band->next_local_refresh = TIME_MIN;
- in_band->dev_name = NULL;
*in_bandp = in_band;
}
diff --git a/secchan/in-band.h b/secchan/in-band.h
index 1e13a6a..736ad76 100644
--- a/secchan/in-band.h
+++ b/secchan/in-band.h
@@ -21,16 +21,21 @@
struct dpif;
struct in_band;
+struct odp_actions;
struct ofproto;
struct rconn;
struct secchan;
struct settings;
struct switch_status;
-void in_band_create(struct ofproto *, struct switch_status *,
+void in_band_create(struct ofproto *, struct dpif *, struct switch_status *,
struct rconn *controller, struct in_band **);
void in_band_destroy(struct in_band *);
void in_band_run(struct in_band *);
+bool in_band_msg_in_hook(struct in_band *, const flow_t *,
+ const struct ofpbuf *packet);
+bool in_band_rule_check(struct in_band *, const flow_t *,
+ const struct odp_actions *);
void in_band_wait(struct in_band *);
void in_band_flushed(struct in_band *);
diff --git a/secchan/ofproto.c b/secchan/ofproto.c
index ad1aa44..acbd83b 100644
--- a/secchan/ofproto.c
+++ b/secchan/ofproto.c
@@ -433,8 +433,8 @@ ofproto_set_in_band(struct ofproto *p, bool in_band)
{
if (in_band != (p->in_band != NULL)) {
if (in_band) {
- in_band_create(p, p->switch_status, p->controller->rconn,
- &p->in_band);
+ in_band_create(p, &p->dpif, p->switch_status,
+ p->controller->rconn, &p->in_band);
return 0;
} else {
ofproto_set_discovery(p, false, NULL, true);
@@ -2105,6 +2105,10 @@ xlate_actions(const union ofp_action *in, size_t n_in,
ctx.tags = tags ? tags : &no_tags;
ctx.may_setup_flow = true;
do_xlate_actions(in, n_in, &ctx);
+ if (!in_band_rule_check(ofproto->in_band, flow, out)) {
+ printf("xxx in_band_rule_check returned false\n");
+ ctx.may_setup_flow = false;
+ }
if (may_setup_flow) {
*may_setup_flow = ctx.may_setup_flow;
}
@@ -2997,6 +3001,21 @@ handle_odp_msg(struct ofproto *p, struct ofpbuf *packet)
struct ofpbuf payload;
flow_t flow;
+ payload.data = msg + 1;
+ payload.size = msg->length - sizeof *msg;
+ flow_extract(&payload, 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. */
+ if (in_band_msg_in_hook(p->in_band, &flow, &payload)) {
+ union odp_action action;
+
+ memset(&action, 0, sizeof(action));
+ action.output.type = ODPAT_OUTPUT;
+ action.output.port = ODPP_LOCAL;
+ dpif_execute(&p->dpif, flow.in_port, &action, 1, &payload);
+ }
+
/* Handle controller actions. */
if (msg->type == _ODPL_ACTION_NR) {
COVERAGE_INC(ofproto_ctlr_action);
@@ -3005,10 +3024,6 @@ handle_odp_msg(struct ofproto *p, struct ofpbuf *packet)
return;
}
- payload.data = msg + 1;
- payload.size = msg->length - sizeof *msg;
- flow_extract(&payload, msg->port, &flow);
-
rule = lookup_valid_rule(p, &flow);
if (!rule) {
/* Don't send a packet-in if OFPPC_NO_PACKET_IN asserted. */
--
1.6.3.1
More information about the discuss
mailing list