[ovs-discuss] [ACL 2/3] vswitchd: Implement local ACL functionality.
Jesse Gross
jesse at nicira.com
Mon Aug 3 18:21:34 UTC 2009
Allows ACL's to be locally configured and applied when the switch is
not connected to a controller. ACL's may be added to the configuration
file and will applied to specified switch ports. Ingress rules generate
OpenFlow entries, while egress rules utilize a new filter to remove output
ports after normal processing has taken place.
---
lib/acl.c | 629 ++++++++++++++++++++++++++++++++++++++++++++++++++
lib/acl.h | 36 +++
lib/automake.mk | 2 +
lib/vlog-modules.def | 1 +
vswitchd/bridge.c | 41 +++-
5 files changed, 703 insertions(+), 6 deletions(-)
create mode 100644 lib/acl.c
create mode 100644 lib/acl.h
diff --git a/lib/acl.c b/lib/acl.c
new file mode 100644
index 0000000..bc204f3
--- /dev/null
+++ b/lib/acl.c
@@ -0,0 +1,629 @@
+/*
+ * Copyright (c) 2009 Nicira Networks.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include "acl.h"
+
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <fnmatch.h>
+#include <netinet/in.h>
+
+#include "cfg.h"
+#include "classifier.h"
+#include "flow.h"
+#include "hmap.h"
+#include "packets.h"
+#include "shash.h"
+#include "svec.h"
+#include "util.h"
+#include "vlog.h"
+
+#define THIS_MODULE VLM_acl
+
+struct acl {
+ const char *port_name; /* Name of port */
+ struct ofproto *ofproto; /* Bridge OpenFlow switch */
+ uint16_t cur_ofp_port; /* The port in rules are installed on */
+ struct classifier out_rules; /* Lookup table for applying egress ACL's */
+ bool has_in_rules; /* Have in rules been applied to this port? */
+ bool has_out_rules; /* Have out rules been applied to this port? */
+};
+
+struct acl_rule {
+ flow_t flow; /* Flow entry for this rule */
+ uint32_t wildcards; /* Wildcards for this rule */
+ unsigned int priority; /* Rule priority */
+ struct cls_rule cr; /* Classifier rule for out ACL's */
+ bool permit; /* Allow further processing or drop packets */
+};
+
+struct acl_group {
+ int size; /* Size of group */
+ struct acl_rule **rules; /* Rules in group */
+};
+
+/* Whether ACL's are currently enabled. */
+static bool acls_active = true;
+
+/* Mapping of group name to struct acl_group *. */
+static struct shash acls = SHASH_INITIALIZER(&acls);
+
+/* Old configuration, used to check if we need to update. */
+static struct svec old_cfg = SVEC_EMPTY_INITIALIZER;
+
+/* The action to be taken if a packet is permitted. */
+static union ofp_action permit_action;
+
+static void install_rules(const char *group_name, uint16_t ofp_port,
+ bool in_rule, struct acl *info);
+static void update_rules(void);
+static bool parse_acl(const char *acl, unsigned int priority,
+ struct acl_rule **rule);
+static bool extract_ip_mask(const char *mask, int wildcard_shift,
+ int of_wildcard_mask, uint32_t *address,
+ uint32_t *wildcards);
+static bool extract_port(const char *str, int wildcard_val, uint16_t *port,
+ uint32_t *wildcards);
+static void add_default_acl(struct acl_rule **rule);
+
+void
+acl_init(void)
+{
+ memset(&permit_action, 0, sizeof permit_action);
+ permit_action.type = htons(OFPAT_OUTPUT);
+ permit_action.output.len = htons(sizeof permit_action);
+ permit_action.output.port = htons(OFPP_NORMAL);
+
+ acl_reconfigure();
+}
+
+void
+acl_reconfigure(void)
+{
+ struct svec new_cfg = SVEC_EMPTY_INITIALIZER;
+ struct shash_node *old_node;
+ struct acl_group *old_rule_set;
+ int i;
+
+ /* ACL's are switch local, so disable if a controller is configured. */
+ if (cfg_has_section("acl")) {
+ if (cfg_has("mgmt.controller")) {
+ if (acls_active) {
+ VLOG_WARN("CONTROLLER CONFIGURED, DISABLING ACL'S");
+ acls_active = false;
+ }
+ } else {
+ acls_active = true;
+ }
+ } else {
+ acls_active = false;
+ }
+
+ /* Only reconfigure if something actually changed. */
+ if (acls_active) {
+ cfg_get_section(&new_cfg, "acl");
+ if (svec_equal(&old_cfg, &new_cfg)) {
+ svec_destroy(&new_cfg);
+ return;
+ } else {
+ svec_swap(&old_cfg, &new_cfg);
+ svec_destroy(&new_cfg);
+ }
+ }
+
+ /* Remove old entries. */
+ HMAP_FOR_EACH(old_node, struct shash_node, node, &acls.map) {
+ old_rule_set = old_node->data;
+ for (i = 0; i < old_rule_set->size; i++) {
+ free(old_rule_set->rules[i]);
+ }
+ free(old_rule_set);
+ }
+ shash_clear(&acls);
+
+ if (!acls_active) {
+ return;
+ }
+
+ /* Add new entries. */
+ update_rules();
+}
+
+bool
+acl_is_active(void)
+{
+ return acls_active;
+}
+
+void
+acl_iface_init(const char *port_name, struct ofproto *ofproto,
+ struct acl **info)
+{
+ *info = xmalloc(sizeof **info);
+ (*info)->port_name = port_name;
+ (*info)->ofproto = ofproto;
+ classifier_init(&(*info)->out_rules);
+ (*info)->has_in_rules = false;
+ (*info)->has_out_rules = false;
+}
+
+void
+acl_iface_reconfigure(struct acl *info, uint16_t ofp_port)
+{
+ flow_t flow;
+ uint32_t wildcards;
+ const char *acl_group_name;
+ struct svec priorities = SVEC_EMPTY_INITIALIZER;
+ int i;
+ const char *glob;
+
+ memset(&flow, 0, sizeof flow);
+ flow.in_port = ofp_port;
+ wildcards = OFPFW_ALL & ~OFPFW_IN_PORT;
+
+ /* Clear out old flows associated with ACL's. Since ACL's are only active
+ * when there is no controller, only our flows should be in here. */
+ if (info->has_in_rules) {
+ ofproto_delete_flows_wildcarded(info->ofproto, &flow, wildcards);
+ info->has_in_rules = false;
+ }
+
+ if (info->has_out_rules) {
+ classifier_destroy(&info->out_rules);
+ classifier_init(&info->out_rules);
+ info->has_out_rules = false;
+ }
+
+ if (!acls_active) {
+ return;
+ }
+
+ /* Add flows for ingress rules. */
+ if (!info->has_in_rules) {
+ acl_group_name = cfg_get_string(0, "acl.port.%s.in", info->port_name);
+ if (acl_group_name) {
+ install_rules(acl_group_name, ofp_port, true, info);
+ }
+ }
+
+ /* Add to classifier for egress rules. */
+ if (!info->has_out_rules) {
+ acl_group_name = cfg_get_string(0, "acl.port.%s.out", info->port_name);
+ if (acl_group_name) {
+ install_rules(acl_group_name, ofp_port, false, info);
+ }
+ }
+
+ /* Wildcarded rules. */
+ if (!info->has_in_rules || !info->has_out_rules) {
+ cfg_get_subsections(&priorities, "acl.default");
+ svec_sort(&priorities);
+
+ for (i = 0; i < priorities.n; i++) {
+ glob = cfg_get_string(0, "acl.default.%s.match",
+ priorities.names[i]);
+ if (glob) {
+ if (fnmatch(glob, info->port_name, 0) == 0) {
+ if (!info->has_in_rules) {
+ acl_group_name = cfg_get_string(0,
+ "acl.default.%s.in",
+ priorities.names[i]);
+ if (acl_group_name) {
+ install_rules(acl_group_name, ofp_port, true, info);
+ }
+ }
+ if (!info->has_out_rules) {
+ acl_group_name = cfg_get_string(0,
+ "acl.default.%s.out",
+ priorities.names[i]);
+ if (acl_group_name) {
+ install_rules(acl_group_name, ofp_port, false,
+ info);
+ }
+ }
+ if (info->has_in_rules && info->has_out_rules) {
+ break;
+ }
+ }
+ } else {
+ VLOG_WARN("invalid glob when processing default acl's,"
+ " skipping");
+ }
+ }
+ svec_destroy(&priorities);
+ }
+
+ /* No match, install a default ingress flow. */
+ if (!info->has_in_rules) {
+ ofproto_add_flow(info->ofproto, &flow, wildcards, 0, &permit_action,
+ 1, 0);
+ info->has_in_rules = true;
+ }
+
+ info->cur_ofp_port = ofp_port;
+}
+
+static void
+install_rules(const char *group_name, uint16_t ofp_port, bool in_rule,
+ struct acl *info)
+{
+ struct acl_group *access_rules;
+ int i;
+ flow_t flow;
+ uint32_t wildcards;
+
+ access_rules = shash_find_data(&acls, group_name);
+ if (access_rules) {
+ for (i = 0; i < access_rules->size; i++) {
+ if (access_rules->rules[i]) {
+ if (in_rule) {
+ flow = access_rules->rules[i]->flow;
+ wildcards = access_rules->rules[i]->wildcards;
+
+ flow.in_port = ofp_port;
+ wildcards &= ~OFPFW_IN_PORT;
+
+ ofproto_add_flow(info->ofproto, &flow, wildcards,
+ access_rules->rules[i]->priority,
+ access_rules->rules[i]->permit ?
+ &permit_action : NULL,
+ access_rules->rules[i]->permit ? 1 : 0, 0);
+
+ info->has_in_rules = true;
+ } else {
+ classifier_insert(&info->out_rules,
+ &access_rules->rules[i]->cr);
+ info->has_out_rules = true;
+ }
+ }
+ }
+ } else {
+ VLOG_WARN("acl group '%s' not found", group_name);
+ }
+}
+
+void
+acl_iface_destroy(struct acl *info)
+{
+ flow_t flow;
+
+ if (info->has_in_rules) {
+ memset(&flow, 0, sizeof flow);
+ flow.in_port = info->cur_ofp_port;
+ ofproto_delete_flows_wildcarded(info->ofproto, &flow,
+ OFPFW_ALL & ~OFPFW_IN_PORT);
+ }
+ classifier_destroy(&info->out_rules);
+ free(info);
+}
+
+bool
+acl_iface_output_filter(struct acl *info, const flow_t *flow) {
+
+ struct cls_rule *cls_rule;
+ struct acl_rule *rule;
+
+ if (!info->has_out_rules) {
+ return true;
+ }
+
+ cls_rule = classifier_lookup(&info->out_rules, flow);
+ assert(cls_rule); /* All rule sets should end with a wildcarded entry. */
+
+ rule = CONTAINER_OF(cls_rule, struct acl_rule, cr);
+
+ return rule->permit;
+}
+
+static void
+update_rules(void)
+{
+ struct svec groups = SVEC_EMPTY_INITIALIZER;
+ struct svec priorities = SVEC_EMPTY_INITIALIZER;
+ int i, j;
+ const char *acl;
+ struct acl_group *rule_set;
+ bool final_rule;
+
+ /* Create parsed flow entries for each ACL. */
+ cfg_get_subsections(&groups, "acl.group");
+
+ for (i = 0; i < groups.n; i++) {
+ svec_clear(&priorities);
+
+ cfg_get_subsections(&priorities, "acl.group.%s", groups.names[i]);
+ svec_sort(&priorities);
+
+ rule_set = xmalloc(sizeof *rule_set);
+ rule_set->size = priorities.n + 1;
+ rule_set->rules = xcalloc(rule_set->size, sizeof *rule_set->rules);
+
+ for (j = 0; j < priorities.n; j++) {
+ acl = cfg_get_string(0, "acl.group.%s.%s", groups.names[i],
+ priorities.names[j]);
+ if (acl) {
+ final_rule = parse_acl(acl, priorities.n - j,
+ &rule_set->rules[priorities.n - j]);
+
+ if (final_rule) {
+ break;
+ }
+ } else {
+ VLOG_WARN("invalid rule when processing acl's, skipping");
+ }
+ }
+
+ if (!final_rule) {
+ add_default_acl(&rule_set->rules[0]);
+ }
+
+ shash_add(&acls, groups.names[i], rule_set);
+ }
+
+ svec_destroy(&priorities);
+ svec_destroy(&groups);
+}
+
+/* Returns true if this is a completely wildcarded rule. */
+static bool
+parse_acl(const char *acl_, unsigned int priority, struct acl_rule **rule)
+{
+ char *acl;
+ char *c;
+ int num_args;
+ char action[7];
+ char proto_str[5];
+ char srcip_str[19];
+ char dstip_str[19];
+ char srcport_str[6];
+ char dstport_str[6];
+ flow_t *flow;
+ uint32_t *wildcards;
+
+ *rule = xcalloc(1, sizeof **rule);
+ flow = &(*rule)->flow;
+ wildcards = &(*rule)->wildcards;
+ (*rule)->priority = priority;
+ *wildcards = OFPFW_ALL; /* Wildcard all fields unless overridden. */
+
+ /* ACL's are case insensitive. */
+ acl = xstrdup(acl_);
+ c = acl;
+ while (*c) {
+ *c = tolower(*c);
+ c++;
+ }
+
+ num_args = sscanf(acl, "%6s %4s %18s %18s %5s %5s", action, proto_str,
+ srcip_str, dstip_str, srcport_str, dstport_str);
+
+ if (!num_args || num_args == EOF) {
+ VLOG_WARN("unparsable string when processing acl, skipping; "
+ "bad rule: %s", acl);
+ goto error;
+ }
+
+ /* Rule action */
+
+ if (strcmp(action, "permit") == 0) {
+ (*rule)->permit = true;
+ } else if (strcmp(action, "deny") == 0) {
+ (*rule)->permit = false;
+ } else {
+ VLOG_WARN("unknown action when processing acl, skipping; "
+ "bad rule: %s", acl);
+ goto error;
+ }
+ num_args--;
+ if (!num_args) {
+ goto finished;
+ }
+
+ /* Protocol type */
+
+ if (strcmp(proto_str, "any") == 0) {
+ if (num_args > 1) {
+ VLOG_WARN("protocol 'any' specified, skipping remainder; "
+ "rule: %s", acl);
+ }
+ goto finished;
+ } else if (strcmp(proto_str, "arp") == 0) {
+ flow->dl_type = htons(ETH_TYPE_ARP);
+ *wildcards &= ~OFPFW_DL_TYPE;
+ if (num_args > 1) {
+ VLOG_WARN("protocol 'arp' specified, skipping remainder; "
+ "rule: %s", acl);
+ }
+ goto finished;
+ }
+
+ /* All the following protocols are IP-based. */
+ flow->dl_type = htons(ETH_TYPE_IP);
+ *wildcards &= ~OFPFW_DL_TYPE;
+
+ if (strcmp(proto_str, "tcp") == 0) {
+ flow->nw_proto = IP_TYPE_TCP;
+ *wildcards &= ~OFPFW_NW_PROTO;
+ } else if (strcmp(proto_str, "udp") == 0) {
+ flow->nw_proto = IP_TYPE_UDP;
+ *wildcards &= ~OFPFW_NW_PROTO;
+ } else if (strcmp(proto_str, "icmp") == 0) {
+ flow->nw_proto = IP_TYPE_ICMP;
+ *wildcards &= ~OFPFW_NW_PROTO;
+ } else if (strcmp(proto_str, "ip") == 0) {
+ if (num_args > 1) {
+ VLOG_WARN("protocol 'ip' specified, skipping remainder; "
+ "rule: %s", acl);
+ }
+ goto finished;
+ } else {
+ VLOG_WARN("unknown protocol when processing acl, skipping; "
+ "bad rule: %s", acl);
+ goto error;
+ }
+ num_args--;
+ if (!num_args) {
+ goto finished;
+ }
+
+ /* IP addresses */
+
+ if (!extract_ip_mask(srcip_str, OFPFW_NW_SRC_SHIFT, OFPFW_NW_SRC_MASK,
+ &flow->nw_src, wildcards)) {
+ goto error;
+ }
+ num_args--;
+ if (!num_args) {
+ goto finished;
+ }
+
+ if (!extract_ip_mask(dstip_str, OFPFW_NW_DST_SHIFT, OFPFW_NW_DST_MASK,
+ &flow->nw_dst, wildcards)) {
+ goto error;
+ }
+ num_args--;
+ if (!num_args) {
+ goto finished;
+ }
+
+ /* Ports */
+
+ if (flow->nw_proto == 0) {
+ VLOG_WARN("ip protocol specified, skipping port specifications; "
+ "rule: %s", acl);
+ goto finished;
+ }
+
+ if (!extract_port(srcport_str, OFPFW_TP_SRC, &flow->tp_src, wildcards)) {
+ goto error;
+ }
+ num_args--;
+ if (!num_args) {
+ goto finished;
+ }
+
+ if (!extract_port(dstport_str, OFPFW_TP_DST, &flow->tp_dst, wildcards)) {
+ goto error;
+ }
+ num_args--;
+ if (!num_args) {
+ goto finished;
+ }
+
+error:
+ free(*rule);
+ *rule = NULL;
+
+finished:
+ free(acl);
+
+ if (*rule) {
+ cls_rule_from_flow(&(*rule)->cr, flow, *wildcards, priority);
+ return (*wildcards == OFPFW_ALL);
+ } else {
+ return false;
+ }
+}
+
+/* Returns true if the string parsed correctly. */
+static bool
+extract_ip_mask(const char *mask, int wildcard_shift, int of_wildcard_mask,
+ uint32_t *address, uint32_t *wildcards)
+{
+ char *separator;
+ bool ret = true;
+ char *ip;
+ char *cidr;
+ struct in_addr addr;
+ int wildcard_mask;
+
+ if (strcmp(mask, "any") == 0) {
+ return true;
+ }
+
+ ip = xstrdup(mask);
+
+ separator = strchr(ip, '/');
+ if (separator) {
+ *separator = '\0';
+ }
+
+ if (inet_aton(ip, &addr)) {
+ *address = addr.s_addr;
+ } else {
+ VLOG_WARN("invalid address when processing acl, skipping rule; "
+ "bad address: %s", mask);
+ ret = false;
+ }
+
+ /* Clear the existing wildcard bits. */
+ *wildcards &= ~of_wildcard_mask;
+
+ if (separator && *(separator + 1)) {
+ cidr = separator + 1;
+ wildcard_mask = atoi(cidr);
+ if (wildcard_mask) {
+ /* Wildcards are opposite of CIDR. */
+ wildcard_mask = 32 - wildcard_mask;
+ *wildcards |= wildcard_mask << wildcard_shift;
+ } else {
+ VLOG_WARN("invalid netmask when processing acl, skipping rule; "
+ "bad address: %s", mask);
+ ret = false;
+ }
+ }
+
+ free(ip);
+ return ret;
+}
+
+/* Returns true if the string parsed correctly. */
+static bool
+extract_port(const char *str, int wildcard_val, uint16_t *port,
+ uint32_t *wildcards)
+{
+ unsigned short int port_val;
+
+ if (strcmp(str, "any") != 0) {
+ port_val = atoi(str);
+ if (port_val > 0 && port_val <= USHRT_MAX) {
+ *port = htons(port_val);
+ *wildcards &= ~wildcard_val;
+ } else {
+ VLOG_WARN("invalid port specified, skipping rule; port: %s", str);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void
+add_default_acl(struct acl_rule **rule)
+{
+ struct acl_rule *new_rule;
+
+ /* Create a lowest priority default rule that denies all traffic. */
+ new_rule = *rule = xcalloc(1, sizeof **rule);
+
+ new_rule->permit = false;
+ new_rule->priority = 0;
+ new_rule->wildcards = OFPFW_ALL;
+
+ cls_rule_from_flow(&new_rule->cr, &new_rule->flow, new_rule->wildcards,
+ new_rule->priority);
+}
diff --git a/lib/acl.h b/lib/acl.h
new file mode 100644
index 0000000..220d87f
--- /dev/null
+++ b/lib/acl.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2009 Nicira Networks.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ACL_H
+#define ACL_H 1
+
+#include "ofproto/ofproto.h"
+
+struct acl;
+
+void acl_init(void);
+void acl_reconfigure(void);
+
+bool acl_is_active(void);
+
+void acl_iface_init(const char *port_name, struct ofproto *ofproto,
+ struct acl **info);
+void acl_iface_reconfigure(struct acl *info, uint16_t ofp_port);
+void acl_iface_destroy(struct acl *info);
+
+bool acl_iface_output_filter(struct acl *info, const flow_t *flow);
+
+#endif /* acl.h */
diff --git a/lib/automake.mk b/lib/automake.mk
index b0d10fd..c7a7b70 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -8,6 +8,8 @@
noinst_LIBRARIES += lib/libopenvswitch.a
lib_libopenvswitch_a_SOURCES = \
+ lib/acl.c \
+ lib/acl.h \
lib/backtrace.c \
lib/backtrace.h \
lib/bitmap.c \
diff --git a/lib/vlog-modules.def b/lib/vlog-modules.def
index 849c867..7a8ced5 100644
--- a/lib/vlog-modules.def
+++ b/lib/vlog-modules.def
@@ -15,6 +15,7 @@
*/
/* Modules that can emit log messages. */
+VLOG_MODULE(acl)
VLOG_MODULE(backtrace)
VLOG_MODULE(brcompatd)
VLOG_MODULE(bridge)
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 6b05d13..e89b468 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -29,6 +29,7 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
+#include "acl.h"
#include "bitmap.h"
#include "cfg.h"
#include "coverage.h"
@@ -77,6 +78,7 @@ struct iface {
char *name; /* Host network device name. */
tag_type tag; /* Tag associated with this interface. */
long long delay_expires; /* Time after which 'enabled' may change. */
+ struct acl *acl; /* ACL state information for this interface. */
/* These members are valid only after bridge_reconfigure() causes them to
* be initialized.*/
@@ -310,6 +312,7 @@ bridge_init(void)
}
}
+ acl_init();
bond_init();
bridge_reconfigure();
}
@@ -440,7 +443,7 @@ bridge_reconfigure(void)
{
struct svec old_br, new_br;
struct bridge *br, *next;
- size_t i;
+ size_t i,j;
COVERAGE_INC(bridge_reconfigure);
@@ -476,6 +479,8 @@ bridge_reconfigure(void)
bridge_configure_ssl();
#endif
+ acl_reconfigure();
+
/* Reconfigure all bridges. */
LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
bridge_reconfigure_one(br);
@@ -624,6 +629,18 @@ bridge_reconfigure(void)
brstp_reconfigure(br);
iterate_and_prune_ifaces(br, set_iface_policing, NULL);
}
+ LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
+ for (i = 0; i < br->n_ports; i++) {
+ struct port *port = br->ports[i];
+ if (!port->is_mirror_output_port) {
+ for (j = 0; j < port->n_ifaces; j++) {
+ struct iface *iface = port->ifaces[j];
+ acl_iface_reconfigure(iface->acl,
+ odp_port_to_ofp_port(iface->dp_ifidx));
+ }
+ }
+ }
+ }
}
static void
@@ -1289,8 +1306,13 @@ bridge_reconfigure_controller(struct bridge *br)
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);
+
+ if (!acl_is_active()) {
+ ofproto_add_flow(br->ofproto, &flow, OFPFW_ALL, 0,
+ &action, 1, 0);
+ } else {
+ ofproto_delete_flow(br->ofproto, &flow, OFPFW_ALL, 0);
+ }
ofproto_set_in_band(br->ofproto, false);
ofproto_set_max_backoff(br->ofproto, 1);
@@ -1652,18 +1674,22 @@ compose_dsts(const struct bridge *br, const flow_t *flow, uint16_t vlan,
*tags |= in_port->stp_state_tag;
if (out_port == FLOOD_PORT) {
- /* XXX use ODP_FLOOD if no vlans or bonding. */
+ /* XXX use ODP_FLOOD if no vlans, bonding, or ACL's. */
/* XXX even better, define each VLAN as a datapath port group */
for (i = 0; i < br->n_ports; i++) {
struct port *port = br->ports[i];
if (port != in_port && port_includes_vlan(port, vlan)
&& !port->is_mirror_output_port
- && set_dst(dst, flow, in_port, port, tags)) {
+ && set_dst(dst, flow, in_port, port, tags)
+ && acl_iface_output_filter(iface_from_dp_ifidx(br,
+ dst->dp_ifidx)->acl, flow)) {
mirrors |= port->dst_mirrors;
dst++;
}
}
- } else if (out_port && set_dst(dst, flow, in_port, out_port, tags)) {
+ } else if (out_port && set_dst(dst, flow, in_port, out_port, tags)
+ && acl_iface_output_filter(iface_from_dp_ifidx(br,
+ dst->dp_ifidx)->acl, flow)) {
mirrors |= out_port->dst_mirrors;
dst++;
}
@@ -3000,6 +3026,7 @@ iface_create(struct port *port, const char *name)
VLOG_DBG("attached network device %s to port %s", iface->name, port->name);
+ acl_iface_init(port->name, port->bridge->ofproto, &iface->acl);
bridge_flush(port->bridge);
}
@@ -3012,6 +3039,8 @@ iface_destroy(struct iface *iface)
bool del_active = port->active_iface == iface->port_ifidx;
struct iface *del;
+ acl_iface_destroy(iface->acl);
+
if (iface->dp_ifidx >= 0) {
port_array_set(&br->ifaces, iface->dp_ifidx, NULL);
}
--
1.6.0.4
More information about the discuss
mailing list