datapath: Replace "struct odp_action" by Netlink attributes.
[openvswitch] / vswitchd / bridge.c
index a6530c638d381ffd7870b089b184d85cb18e59cb..8ade873faf5133c7043374c7fb1dbef7ddf60b78 100644 (file)
@@ -45,6 +45,7 @@
 #include "list.h"
 #include "mac-learning.h"
 #include "netdev.h"
+#include "netlink.h"
 #include "odp-util.h"
 #include "ofp-print.h"
 #include "ofpbuf.h"
@@ -1945,15 +1946,16 @@ bridge_fetch_dp_ifaces(struct bridge *br)
 /* Bridge packet processing functions. */
 
 static int
-bond_hash(const uint8_t mac[ETH_ADDR_LEN])
+bond_hash(const uint8_t mac[ETH_ADDR_LEN], uint16_t vlan)
 {
-    return hash_bytes(mac, ETH_ADDR_LEN, 0) & BOND_MASK;
+    return hash_bytes(mac, ETH_ADDR_LEN, vlan) & BOND_MASK;
 }
 
 static struct bond_entry *
-lookup_bond_entry(const struct port *port, const uint8_t mac[ETH_ADDR_LEN])
+lookup_bond_entry(const struct port *port, const uint8_t mac[ETH_ADDR_LEN],
+                  uint16_t vlan)
 {
-    return &port->bond_hash[bond_hash(mac)];
+    return &port->bond_hash[bond_hash(mac, vlan)];
 }
 
 static int
@@ -1988,7 +1990,7 @@ bond_choose_iface(const struct port *port)
 
 static bool
 choose_output_iface(const struct port *port, const uint8_t *dl_src,
-                    uint16_t *dp_ifidx, tag_type *tags)
+                    uint16_t vlan, uint16_t *dp_ifidx, tag_type *tags)
 {
     struct iface *iface;
 
@@ -1996,7 +1998,7 @@ choose_output_iface(const struct port *port, const uint8_t *dl_src,
     if (port->n_ifaces == 1) {
         iface = port->ifaces[0];
     } else {
-        struct bond_entry *e = lookup_bond_entry(port, dl_src);
+        struct bond_entry *e = lookup_bond_entry(port, dl_src, vlan);
         if (e->iface_idx < 0 || e->iface_idx >= port->n_ifaces
             || !port->ifaces[e->iface_idx]->enabled) {
             /* XXX select interface properly.  The current interface selection
@@ -2233,7 +2235,8 @@ set_dst(struct dst *p, const struct flow *flow,
               : in_port->vlan >= 0 ? in_port->vlan
               : flow->vlan_tci == 0 ? OFP_VLAN_NONE
               : vlan_tci_to_vid(flow->vlan_tci));
-    return choose_output_iface(out_port, flow->dl_src, &p->dp_ifidx, tags);
+    return choose_output_iface(out_port, flow->dl_src, p->vlan,
+                               &p->dp_ifidx, tags);
 }
 
 static void
@@ -2422,7 +2425,7 @@ print_dsts(const struct dst *dsts, size_t n)
 static void
 compose_actions(struct bridge *br, const struct flow *flow, uint16_t vlan,
                 const struct port *in_port, const struct port *out_port,
-                tag_type *tags, struct odp_actions *actions,
+                tag_type *tags, struct ofpbuf *actions,
                 uint16_t *nf_output_iface)
 {
     struct dst dsts[DP_MAX_PORTS * (MAX_MIRRORS + 1)];
@@ -2438,19 +2441,18 @@ compose_actions(struct bridge *br, const struct flow *flow, uint16_t vlan,
         cur_vlan = OFP_VLAN_NONE;
     }
     for (p = dsts; p < &dsts[n_dsts]; p++) {
-        union odp_action *a;
         if (p->vlan != cur_vlan) {
             if (p->vlan == OFP_VLAN_NONE) {
-                odp_actions_add(actions, ODPAT_STRIP_VLAN);
+                nl_msg_put_flag(actions, ODPAT_STRIP_VLAN);
             } else {
-                a = odp_actions_add(actions, ODPAT_SET_DL_TCI);
-                a->dl_tci.tci = htons(p->vlan & VLAN_VID_MASK);
-                a->dl_tci.tci |= flow->vlan_tci & htons(VLAN_PCP_MASK);
+                ovs_be16 tci;
+                tci = htons(p->vlan & VLAN_VID_MASK);
+                tci |= flow->vlan_tci & htons(VLAN_PCP_MASK);
+                nl_msg_put_be16(actions, ODPAT_SET_DL_TCI, tci);
             }
             cur_vlan = p->vlan;
         }
-        a = odp_actions_add(actions, ODPAT_OUTPUT);
-        a->output.port = p->dp_ifidx;
+        nl_msg_put_u32(actions, ODPAT_OUTPUT, p->dp_ifidx);
     }
 }
 
@@ -2643,7 +2645,7 @@ is_admissible(struct bridge *br, const struct flow *flow, bool have_packet,
  * not at all, if 'packet' was NULL. */
 static bool
 process_flow(struct bridge *br, const struct flow *flow,
-             const struct ofpbuf *packet, struct odp_actions *actions,
+             const struct ofpbuf *packet, struct ofpbuf *actions,
              tag_type *tags, uint16_t *nf_output_iface)
 {
     struct port *in_port;
@@ -2694,7 +2696,7 @@ done:
 
 static bool
 bridge_normal_ofhook_cb(const struct flow *flow, const struct ofpbuf *packet,
-                        struct odp_actions *actions, tag_type *tags,
+                        struct ofpbuf *actions, tag_type *tags,
                         uint16_t *nf_output_iface, void *br_)
 {
     struct iface *iface;
@@ -2716,14 +2718,15 @@ bridge_normal_ofhook_cb(const struct flow *flow, const struct ofpbuf *packet,
 
 static void
 bridge_account_flow_ofhook_cb(const struct flow *flow, tag_type tags,
-                              const union odp_action *actions,
-                              size_t n_actions, unsigned long long int n_bytes,
-                              void *br_)
+                              const struct nlattr *actions,
+                              unsigned int actions_len,
+                              unsigned long long int n_bytes, void *br_)
 {
     struct bridge *br = br_;
-    const union odp_action *a;
+    const struct nlattr *a;
     struct port *in_port;
     tag_type dummy = 0;
+    unsigned int left;
     int vlan;
 
     /* Feed information from the active flows back into the learning table to
@@ -2741,12 +2744,15 @@ bridge_account_flow_ofhook_cb(const struct flow *flow, tag_type tags,
     if (!br->has_bonded_ports) {
         return;
     }
-    for (a = actions; a < &actions[n_actions]; a++) {
-        if (a->type == ODPAT_OUTPUT) {
-            struct port *out_port = port_from_dp_ifidx(br, a->output.port);
+    NL_ATTR_FOR_EACH_UNSAFE (a, left, actions, actions_len) {
+        if (nl_attr_type(a) == ODPAT_OUTPUT) {
+            struct port *out_port = port_from_dp_ifidx(br, nl_attr_get_u32(a));
             if (out_port && out_port->n_ifaces >= 2) {
+                uint16_t vlan = (flow->vlan_tci
+                                 ? vlan_tci_to_vid(flow->vlan_tci)
+                                 : OFP_VLAN_NONE);
                 struct bond_entry *e = lookup_bond_entry(out_port,
-                                                         flow->dl_src);
+                                                         flow->dl_src, vlan);
                 e->tx_bytes += n_bytes;
             }
         }
@@ -3100,7 +3106,7 @@ bond_send_learning_packets(struct port *port)
         int retval;
 
         if (e->port == port->port_idx
-            || !choose_output_iface(port, e->mac, &dp_ifidx, &tags)) {
+            || !choose_output_iface(port, e->mac, e->vlan, &dp_ifidx, &tags)) {
             continue;
         }
 
@@ -3246,9 +3252,10 @@ bond_unixctl_show(struct unixctl_conn *conn,
             LIST_FOR_EACH (me, lru_node, &port->bridge->ml->lrus) {
                 uint16_t dp_ifidx;
                 tag_type tags = 0;
-                if (bond_hash(me->mac) == hash
+                if (bond_hash(me->mac, me->vlan) == hash
                     && me->port != port->port_idx
-                    && choose_output_iface(port, me->mac, &dp_ifidx, &tags)
+                    && choose_output_iface(port, me->mac, me->vlan,
+                                           &dp_ifidx, &tags)
                     && dp_ifidx == iface->dp_ifidx)
                 {
                     ds_put_format(&ds, "\t\t"ETH_ADDR_FMT"\n",
@@ -3410,16 +3417,32 @@ bond_unixctl_disable_slave(struct unixctl_conn *conn, const char *args,
 }
 
 static void
-bond_unixctl_hash(struct unixctl_conn *conn, const char *args,
+bond_unixctl_hash(struct unixctl_conn *conn, const char *args_,
                   void *aux OVS_UNUSED)
 {
+    char *args = (char *) args_;
     uint8_t mac[ETH_ADDR_LEN];
     uint8_t hash;
     char *hash_cstr;
+    unsigned int vlan;
+    char *mac_s, *vlan_s;
+    char *save_ptr = NULL;
+
+    mac_s  = strtok_r(args, " ", &save_ptr);
+    vlan_s = strtok_r(NULL, " ", &save_ptr);
+
+    if (vlan_s) {
+        if (sscanf(vlan_s, "%u", &vlan) != 1) {
+            unixctl_command_reply(conn, 501, "invalid vlan");
+            return;
+        }
+    } else {
+        vlan = OFP_VLAN_NONE;
+    }
 
-    if (sscanf(args, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))
+    if (sscanf(mac_s, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))
         == ETH_ADDR_SCAN_COUNT) {
-        hash = bond_hash(mac);
+        hash = bond_hash(mac, vlan);
 
         hash_cstr = xasprintf("%u", hash);
         unixctl_command_reply(conn, 200, hash_cstr);