- in_band->controller_ip = controller_ip;
-
- remote_mac = get_remote_mac(in_band);
- local_mac = get_local_mac(in_band);
-
- if (local_mac) {
- /* 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);
- memcpy(flow.dl_src, local_mac, ETH_ADDR_LEN);
- flow.nw_proto = IP_TYPE_UDP;
- flow.tp_src = htons(DHCP_CLIENT_PORT);
- flow.tp_dst = htons(DHCP_SERVER_PORT);
- set_up_flow(in_band, IBR_FROM_LOCAL_DHCP, &flow,
- (OFPFW_IN_PORT | OFPFW_DL_TYPE | OFPFW_DL_SRC
- | OFPFW_NW_PROTO | OFPFW_TP_SRC | OFPFW_TP_DST),
- 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);
- flow.nw_proto = ARP_OP_REPLY;
- set_up_flow(in_band, IBR_TO_LOCAL_ARP, &flow,
- (OFPFW_DL_TYPE | OFPFW_DL_DST | OFPFW_NW_PROTO),
- 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);
- flow.nw_proto = ARP_OP_REQUEST;
- set_up_flow(in_band, IBR_FROM_LOCAL_ARP, &flow,
- (OFPFW_DL_TYPE | OFPFW_DL_SRC | OFPFW_NW_PROTO),
- OFPP_NORMAL);
- } else {
- drop_flow(in_band, IBR_TO_LOCAL_ARP);
- drop_flow(in_band, IBR_FROM_LOCAL_ARP);
+
+ for (i = 0; i < ib->n_remote_addrs; i++) {
+ const struct sockaddr_in *a = &ib->remote_addrs[i];
+
+ if (!i || a->sin_addr.s_addr != a[-1].sin_addr.s_addr) {
+ /* (f) Allow ARP replies containing the remote's IP address as a
+ * target. */
+ init_rule(&rule, IBR_TO_REMOTE_ARP);
+ set_dl_type(&rule, htons(ETH_TYPE_ARP));
+ set_nw_proto(&rule, ARP_OP_REPLY);
+ set_nw_dst(&rule, a->sin_addr);
+ cb(ib, &rule);
+
+ /* (g) Allow ARP requests containing the remote's IP address as a
+ * source. */
+ init_rule(&rule, IBR_FROM_REMOTE_ARP);
+ set_dl_type(&rule, htons(ETH_TYPE_ARP));
+ set_nw_proto(&rule, ARP_OP_REQUEST);
+ set_nw_src(&rule, a->sin_addr);
+ cb(ib, &rule);
+ }
+
+ if (!i
+ || a->sin_addr.s_addr != a[-1].sin_addr.s_addr
+ || a->sin_port != a[-1].sin_port) {
+ /* (h) Allow TCP traffic to the remote's IP and port. */
+ init_rule(&rule, IBR_TO_REMOTE_TCP);
+ set_dl_type(&rule, htons(ETH_TYPE_IP));
+ set_nw_proto(&rule, IP_TYPE_TCP);
+ set_nw_dst(&rule, a->sin_addr);
+ set_tp_dst(&rule, a->sin_port);
+ cb(ib, &rule);
+
+ /* (i) Allow TCP traffic from the remote's IP and port. */
+ init_rule(&rule, IBR_FROM_REMOTE_TCP);
+ set_dl_type(&rule, htons(ETH_TYPE_IP));
+ set_nw_proto(&rule, IP_TYPE_TCP);
+ set_nw_src(&rule, a->sin_addr);
+ set_tp_src(&rule, a->sin_port);
+ cb(ib, &rule);
+ }
+ }
+}
+
+static void
+drop_rule(struct in_band *ib, const struct in_band_rule *rule)
+{
+ ofproto_delete_flow(ib->ofproto, &rule->flow,
+ rule->wildcards, rule->priority);
+}
+
+/* Drops from the flow table all of the flows set up by 'ib', then clears out
+ * the information about the installed flows so that they can be filled in
+ * again if necessary. */
+static void
+drop_rules(struct in_band *ib)
+{
+ /* Drop rules. */
+ make_rules(ib, drop_rule);
+
+ /* Clear out state. */
+ memset(ib->installed_local_mac, 0, sizeof ib->installed_local_mac);
+
+ free(ib->remote_addrs);
+ ib->remote_addrs = NULL;
+ ib->n_remote_addrs = 0;
+
+ free(ib->remote_macs);
+ ib->remote_macs = NULL;
+ ib->n_remote_macs = 0;
+}
+
+static void
+add_rule(struct in_band *ib, const struct in_band_rule *rule)
+{
+ union ofp_action action;
+
+ action.type = htons(OFPAT_OUTPUT);
+ action.output.len = htons(sizeof action);
+ action.output.port = htons(OFPP_NORMAL);
+ action.output.max_len = htons(0);
+ ofproto_add_flow(ib->ofproto, &rule->flow, rule->wildcards,
+ rule->priority, &action, 1, 0);
+}
+
+/* Inserts flows into the flow table for the current state of 'ib'. */
+static void
+add_rules(struct in_band *ib)
+{
+ make_rules(ib, add_rule);
+}
+
+static int
+compare_addrs(const void *a_, const void *b_)
+{
+ const struct sockaddr_in *a = a_;
+ const struct sockaddr_in *b = b_;
+ int cmp;
+
+ cmp = memcmp(&a->sin_addr.s_addr,
+ &b->sin_addr.s_addr,
+ sizeof a->sin_addr.s_addr);
+ if (cmp) {
+ return cmp;