ofproto: Take responsibility for connectivity fault management (CFM).
[openvswitch] / vswitchd / bridge.c
index c8b50d7136bb7750a997290f4de926860effe28f..c082e5da0cba7ac171e6331ab9087cdc6e98572a 100644 (file)
@@ -112,7 +112,6 @@ struct iface {
     bool enabled;               /* May be chosen for flows? */
     bool up;                    /* Is the interface up? */
     const char *type;           /* Usually same as cfg->type. */
-    struct cfm *cfm;            /* Connectivity Fault Management */
     const struct ovsrec_interface *cfg;
 
     /* LACP information. */
@@ -185,6 +184,7 @@ struct port {
     /* LACP information. */
     struct lacp *lacp;          /* LACP object. NULL if LACP is disabled. */
     bool lacp_active;           /* True if LACP is active */
+    bool lacp_fast;             /* True if LACP is in fast mode. */
     uint16_t lacp_priority;     /* LACP system priority. */
 
     /* SLB specific bonding info. */
@@ -305,15 +305,14 @@ static void iface_set_ofport(const struct ovsrec_interface *, int64_t ofport);
 static void iface_update_qos(struct iface *, const struct ovsrec_qos *);
 static void iface_update_cfm(struct iface *);
 static void iface_refresh_cfm_stats(struct iface *iface);
-static void iface_send_packet(struct iface *, struct ofpbuf *packet);
-static void iface_update_carrier(struct iface *, bool carrier);
+static void iface_update_carrier(struct iface *);
+static bool iface_get_carrier(const struct iface *);
 
 static void shash_from_ovs_idl_map(char **keys, char **values, size_t n,
                                    struct shash *);
 static void shash_to_ovs_idl_map(struct shash *,
                                  char ***keys, char ***values, size_t *n);
 
-
 /* Hooks into ofproto processing. */
 static struct ofhooks bridge_ofhooks;
 \f
@@ -725,7 +724,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
                 /* Update 'iface'. */
                 if (iface) {
                     iface->netdev = netdev;
-                    iface->enabled = netdev_get_carrier(iface->netdev);
+                    iface->enabled = iface_get_carrier(iface);
                     iface->up = iface->enabled;
                 }
             } else if (iface && iface->netdev) {
@@ -1193,8 +1192,7 @@ iface_refresh_status(struct iface *iface)
 
 
     ovsrec_interface_set_link_state(iface->cfg,
-                                    netdev_get_carrier(iface->netdev)
-                                    ? "up" : "down");
+                                    iface_get_carrier(iface) ? "up" : "down");
 
     error = netdev_get_mtu(iface->netdev, &mtu);
     if (!error && mtu != INT_MAX) {
@@ -1209,12 +1207,12 @@ iface_refresh_status(struct iface *iface)
 static void
 iface_refresh_cfm_stats(struct iface *iface)
 {
-    size_t i;
-    struct cfm *cfm;
     const struct ovsrec_monitor *mon;
+    const struct cfm *cfm;
+    size_t i;
 
     mon = iface->cfg->monitor;
-    cfm = iface->cfm;
+    cfm = ofproto_iface_get_cfm(iface->port->bridge->ofproto, iface->dp_ifidx);
 
     if (!cfm || !mon) {
         return;
@@ -2995,14 +2993,7 @@ bridge_special_ofhook_cb(const struct flow *flow,
 
     iface = iface_from_dp_ifidx(br, flow->in_port);
 
-    if (cfm_should_process_flow(flow)) {
-
-        if (iface && packet && iface->cfm) {
-            COVERAGE_INC(bridge_process_cfm);
-            cfm_process_heartbeat(iface->cfm, packet);
-        }
-        return false;
-    } else if (flow->dl_type == htons(ETH_TYPE_LACP)) {
+    if (flow->dl_type == htons(ETH_TYPE_LACP)) {
 
         if (iface && iface->port->lacp && packet) {
             const struct lacp_pdu *pdu = parse_lacp_packet(packet);
@@ -3426,9 +3417,8 @@ bond_send_learning_packets(struct port *port)
     ofpbuf_init(&packet, 128);
     error = n_packets = n_errors = 0;
     LIST_FOR_EACH (e, lru_node, &br->ml->lrus) {
-        union ofp_action actions[2], *a;
-        uint16_t dp_ifidx;
         tag_type tags = 0;
+        uint16_t dp_ifidx;
         struct flow flow;
         int retval;
 
@@ -3444,24 +3434,9 @@ bond_send_learning_packets(struct port *port)
             continue;
         }
 
-        /* Compose actions. */
-        memset(actions, 0, sizeof actions);
-        a = actions;
-        if (e->vlan) {
-            a->vlan_vid.type = htons(OFPAT_SET_VLAN_VID);
-            a->vlan_vid.len = htons(sizeof *a);
-            a->vlan_vid.vlan_vid = htons(e->vlan);
-            a++;
-        }
-        a->output.type = htons(OFPAT_OUTPUT);
-        a->output.len = htons(sizeof *a);
-        a->output.port = htons(odp_port_to_ofp_port(dp_ifidx));
-        a++;
-
         /* Send packet. */
         n_packets++;
-        retval = ofproto_send_packet(br->ofproto, &flow, actions, a - actions,
-                                     &packet);
+        retval = ofproto_send_packet(br->ofproto, dp_ifidx, e->vlan, &packet);
         if (retval) {
             error = retval;
             n_errors++;
@@ -3858,7 +3833,8 @@ lacp_send_pdu_cb(void *aux, const struct lacp_pdu *pdu)
 
         ofpbuf_init(&packet, ETH_HEADER_LEN + LACP_PDU_LEN);
         compose_lacp_packet(&packet, ea, pdu);
-        iface_send_packet(iface, &packet);
+        ofproto_send_packet(iface->port->bridge->ofproto,
+                            iface->dp_ifidx, 0, &packet);
         ofpbuf_uninit(&packet);
     } else {
         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 10);
@@ -3870,8 +3846,6 @@ lacp_send_pdu_cb(void *aux, const struct lacp_pdu *pdu)
 static void
 port_run(struct port *port)
 {
-    size_t i;
-
     if (port->monitor) {
         char *devname;
 
@@ -3881,20 +3855,23 @@ port_run(struct port *port)
 
             iface = port_lookup_iface(port, devname);
             if (iface) {
-                iface_update_carrier(iface, netdev_get_carrier(iface->netdev));
+                iface_update_carrier(iface);
             }
             free(devname);
         }
     } else if (time_msec() >= port->miimon_next_update) {
+        size_t i;
 
         for (i = 0; i < port->n_ifaces; i++) {
             struct iface *iface = port->ifaces[i];
-            iface_update_carrier(iface, netdev_get_miimon(iface->netdev));
+            iface_update_carrier(iface);
         }
         port->miimon_next_update = time_msec() + port->miimon_interval;
     }
 
     if (port->lacp) {
+        size_t i;
+
         for (i = 0; i < port->n_ifaces; i++) {
             struct iface *iface = port->ifaces[i];
             lacp_slave_enable(port->lacp, iface, iface->enabled);
@@ -3904,26 +3881,11 @@ port_run(struct port *port)
     }
 
     bond_run(port);
-
-    for (i = 0; i < port->n_ifaces; i++) {
-        struct iface *iface = port->ifaces[i];
-
-        if (iface->cfm) {
-            struct ofpbuf *packet = cfm_run(iface->cfm);
-            if (packet) {
-                iface_send_packet(iface, packet);
-                ofpbuf_uninit(packet);
-                free(packet);
-            }
-        }
-    }
 }
 
 static void
 port_wait(struct port *port)
 {
-    size_t i;
-
     if (port->monitor) {
         netdev_monitor_poll_wait(port->monitor);
     } else {
@@ -3935,13 +3897,6 @@ port_wait(struct port *port)
     }
 
     bond_wait(port);
-
-    for (i = 0; i < port->n_ifaces; i++) {
-        struct iface *iface = port->ifaces[i];
-        if (iface->cfm) {
-            cfm_wait(iface->cfm);
-        }
-    }
 }
 
 static struct port *
@@ -4132,6 +4087,9 @@ port_reconfigure(struct port *port, const struct ovsrec_port *cfg)
     }
     shash_destroy(&new_ifaces);
 
+    port->lacp_fast = !strcmp(get_port_other_config(cfg, "lacp-time", "slow"),
+                             "fast");
+
     lacp_priority =
         atoi(get_port_other_config(cfg, "lacp-system-priority", "0"));
 
@@ -4290,7 +4248,7 @@ port_update_lacp(struct port *port)
 
         lacp_configure(port->lacp, port->name,
                        port->bridge->ea, port->lacp_priority,
-                       port->lacp_active);
+                       port->lacp_active, port->lacp_fast);
 
         for (i = 0; i < port->n_ifaces; i++) {
             struct iface *iface = port->ifaces[i];
@@ -4345,26 +4303,6 @@ port_update_bonding(struct port *port)
 \f
 /* Interface functions. */
 
-static void
-iface_send_packet(struct iface *iface, struct ofpbuf *packet)
-{
-    struct flow flow;
-    union ofp_action action;
-
-    memset(&action, 0, sizeof action);
-    action.output.type = htons(OFPAT_OUTPUT);
-    action.output.len  = htons(sizeof action);
-    action.output.port = htons(odp_port_to_ofp_port(iface->dp_ifidx));
-
-    flow_extract(packet, 0, ODPP_NONE, &flow);
-
-    if (ofproto_send_packet(iface->port->bridge->ofproto, &flow, &action, 1,
-                            packet)) {
-        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
-        VLOG_WARN_RL(&rl, "interface %s: Failed to send packet.", iface->name);
-    }
-}
-
 static struct iface *
 iface_create(struct port *port, const struct ovsrec_interface *if_cfg)
 {
@@ -4434,8 +4372,6 @@ iface_destroy(struct iface *iface)
             bond_send_learning_packets(port);
         }
 
-        cfm_destroy(iface->cfm);
-
         free(iface->name);
         free(iface);
 
@@ -4585,8 +4521,9 @@ iface_delete_queues(unsigned int queue_id,
 }
 
 static void
-iface_update_carrier(struct iface *iface, bool carrier)
+iface_update_carrier(struct iface *iface)
 {
+    bool carrier = iface_get_carrier(iface);
     if (carrier == iface->up) {
         return;
     }
@@ -4637,7 +4574,7 @@ static void
 iface_update_cfm(struct iface *iface)
 {
     size_t i;
-    struct cfm *cfm;
+    struct cfm cfm;
     uint16_t *remote_mps;
     struct ovsrec_monitor *mon;
     uint8_t ea[ETH_ADDR_LEN], maid[CCM_MAID_LEN];
@@ -4645,8 +4582,7 @@ iface_update_cfm(struct iface *iface)
     mon = iface->cfg->monitor;
 
     if (!mon) {
-        cfm_destroy(iface->cfm);
-        iface->cfm = NULL;
+        ofproto_iface_clear_cfm(iface->port->bridge->ofproto, iface->dp_ifidx);
         return;
     }
 
@@ -4661,28 +4597,32 @@ iface_update_cfm(struct iface *iface)
         return;
     }
 
-    if (!iface->cfm) {
-        iface->cfm = cfm_create();
-    }
-
-    cfm           = iface->cfm;
-    cfm->mpid     = mon->mpid;
-    cfm->interval = mon->interval ? *mon->interval : 1000;
+    cfm.mpid     = mon->mpid;
+    cfm.interval = mon->interval ? *mon->interval : 1000;
 
-    memcpy(cfm->eth_src, ea, sizeof cfm->eth_src);
-    memcpy(cfm->maid, maid, sizeof cfm->maid);
+    memcpy(cfm.eth_src, ea, sizeof cfm.eth_src);
+    memcpy(cfm.maid, maid, sizeof cfm.maid);
 
     remote_mps = xzalloc(mon->n_remote_mps * sizeof *remote_mps);
     for(i = 0; i < mon->n_remote_mps; i++) {
         remote_mps[i] = mon->remote_mps[i]->mpid;
     }
-    cfm_update_remote_mps(cfm, remote_mps, mon->n_remote_mps);
+
+    ofproto_iface_set_cfm(iface->port->bridge->ofproto, iface->dp_ifidx,
+                          &cfm, remote_mps, mon->n_remote_mps);
     free(remote_mps);
+}
 
-    if (!cfm_configure(iface->cfm)) {
-        cfm_destroy(iface->cfm);
-        iface->cfm = NULL;
-    }
+/* Read carrier or miimon status directly from 'iface''s netdev, according to
+ * how 'iface''s port is configured.
+ *
+ * Returns true if 'iface' is up, false otherwise. */
+static bool
+iface_get_carrier(const struct iface *iface)
+{
+    return (iface->port->monitor
+            ? netdev_get_carrier(iface->netdev)
+            : netdev_get_miimon(iface->netdev));
 }
 \f
 /* Port mirroring. */