summaryrefslogtreecommitdiff
path: root/ofproto/ofproto-dpif.c
diff options
context:
space:
mode:
authorVasu Dasari <vdasari@gmail.com>2021-06-29 16:43:39 -0400
committerIlya Maximets <i.maximets@ovn.org>2021-07-16 16:21:02 +0200
commitccc24fc88d590e1d89185ee5650c9c5f031c916d (patch)
tree6ea6b770f62ed8e163b392a253402edfa058eb05 /ofproto/ofproto-dpif.c
parentae2424696cff5a8a60db9a961bc366abced77e8d (diff)
downloadopenvswitch-ccc24fc88d590e1d89185ee5650c9c5f031c916d.tar.gz
ofproto-dpif: APIs and CLI option to add/delete static fdb entry.
Currently there is an option to add/flush/show ARP/ND neighbor. This covers L3 side. For L2 side, there is only fdb show command. This commit gives an option to add/del an fdb entry via ovs-appctl. CLI command looks like: To add: ovs-appctl fdb/add <bridge> <port> <vlan> <Mac> ovs-appctl fdb/add br0 p1 0 50:54:00:00:00:05 To del: ovs-appctl fdb/del <bridge> <vlan> <Mac> ovs-appctl fdb/del br0 0 50:54:00:00:00:05 Added two new APIs to provide convenient interface to add and delete static-macs. bool xlate_add_static_mac_entry(const struct ofproto_dpif *, ofp_port_t in_port, struct eth_addr dl_src, int vlan); bool xlate_delete_static_mac_entry(const struct ofproto_dpif *, struct eth_addr dl_src, int vlan); 1. Static entry should not age. To indicate that entry being programmed is a static entry, 'expires' field in 'struct mac_entry' will be set to a MAC_ENTRY_AGE_STATIC_ENTRY. A check for this value is made while deleting mac entry as part of regular aging process. 2. Another change to the mac-update logic, when a packet with same dl_src as that of a static-mac entry arrives on any port, the logic will not modify the expires field. 3. While flushing fdb entries, made sure static ones are not evicted. 4. Updated "ovs-appctl fdb/stats-show br0" to display number of static entries in switch Added following tests: ofproto-dpif - static-mac add/del/flush ofproto-dpif - static-mac mac moves Reported-at: https://mail.openvswitch.org/pipermail/ovs-discuss/2019-June/048894.html Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1597752 Signed-off-by: Vasu Dasari <vdasari@gmail.com> Tested-by: Eelco Chaudron <echaudro@redhat.com> Acked-by: Eelco Chaudron <echaudro@redhat.com> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
Diffstat (limited to 'ofproto/ofproto-dpif.c')
-rw-r--r--ofproto/ofproto-dpif.c111
1 files changed, 107 insertions, 4 deletions
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 5ce56adfa..cba49a99e 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -5874,12 +5874,17 @@ ofproto_unixctl_fdb_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
LIST_FOR_EACH (e, lru_node, &ofproto->ml->lrus) {
struct ofbundle *bundle = mac_entry_get_port(ofproto->ml, e);
char name[OFP_MAX_PORT_NAME_LEN];
+ int age = mac_entry_age(ofproto->ml, e);
ofputil_port_to_string(ofbundle_get_a_port(bundle)->up.ofp_port,
- NULL, name, sizeof name);
- ds_put_format(&ds, "%5s %4d "ETH_ADDR_FMT" %3d\n",
- name, e->vlan, ETH_ADDR_ARGS(e->mac),
- mac_entry_age(ofproto->ml, e));
+ NULL, name, sizeof name);
+ ds_put_format(&ds, "%5s %4d "ETH_ADDR_FMT" ",
+ name, e->vlan, ETH_ADDR_ARGS(e->mac));
+ if (MAC_ENTRY_AGE_STATIC_ENTRY == age) {
+ ds_put_format(&ds, "static\n");
+ } else {
+ ds_put_format(&ds, "%3d\n", age);
+ }
}
ovs_rwlock_unlock(&ofproto->ml->rwlock);
unixctl_command_reply(conn, ds_cstr(&ds));
@@ -5887,6 +5892,97 @@ ofproto_unixctl_fdb_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
}
static void
+ofproto_unixctl_fdb_add(struct unixctl_conn *conn, int argc OVS_UNUSED,
+ const char *argv[], void *aux OVS_UNUSED)
+{
+ const struct ofproto_dpif *ofproto;
+ const struct mac_entry *mac_entry;
+ const struct ofbundle *bundle = NULL;
+ struct ds ds = DS_EMPTY_INITIALIZER;
+ struct ofproto_port ofproto_port;
+ ofp_port_t in_port = OFPP_NONE;
+ const char *br_name = argv[1];
+ const char *port_name = argv[2];
+ uint16_t vlan = atoi(argv[3]);
+ struct eth_addr mac;
+ int age;
+
+ ofproto = ofproto_dpif_lookup_by_name(br_name);
+ if (!ofproto) {
+ unixctl_command_reply_error(conn, "no such bridge");
+ return;
+ }
+
+ if (!eth_addr_from_string(argv[4], &mac)) {
+ unixctl_command_reply_error(conn, "bad MAC address");
+ return;
+ }
+
+ if (ofproto_port_query_by_name(&ofproto->up, port_name, &ofproto_port)) {
+ unixctl_command_reply_error(conn,
+ "software error, odp port is present but no ofp port");
+ return;
+ }
+ in_port = ofproto_port.ofp_port;
+ ofproto_port_destroy(&ofproto_port);
+
+ /* Give a bit more information if the entry being added is overriding
+ * an existing entry. */
+ ovs_rwlock_rdlock(&ofproto->ml->rwlock);
+ mac_entry = mac_learning_lookup(ofproto->ml, mac, vlan);
+ if (mac_entry) {
+ bundle = mac_entry_get_port(ofproto->ml, mac_entry);
+ age = mac_entry->expires;
+ }
+ ovs_rwlock_unlock(&ofproto->ml->rwlock);
+
+ if (bundle && (strcmp(bundle->name, port_name) ||
+ age != MAC_ENTRY_AGE_STATIC_ENTRY)) {
+ char old_port_name[OFP_MAX_PORT_NAME_LEN];
+
+ ofputil_port_to_string(ofbundle_get_a_port(bundle)->up.ofp_port,
+ NULL, old_port_name, sizeof old_port_name);
+ ds_put_format(&ds, "Overriding already existing %s entry on %s\n",
+ (age == MAC_ENTRY_AGE_STATIC_ENTRY) ? "static" : "dynamic",
+ old_port_name);
+ }
+
+ if (!xlate_add_static_mac_entry(ofproto, in_port, mac, vlan)) {
+ unixctl_command_reply_error(conn, "could not add static mac entry\n");
+ } else {
+ unixctl_command_reply(conn, ds_cstr(&ds));
+ }
+
+ ds_destroy(&ds);
+}
+
+static void
+ofproto_unixctl_fdb_delete(struct unixctl_conn *conn, int argc OVS_UNUSED,
+ const char *argv[], void *aux OVS_UNUSED)
+{
+ const struct ofproto_dpif *ofproto;
+ const char *br_name = argv[1];
+ uint16_t vlan = atoi(argv[2]);
+ struct eth_addr mac;
+
+ ofproto = ofproto_dpif_lookup_by_name(br_name);
+ if (!ofproto) {
+ unixctl_command_reply_error(conn, "no such bridge");
+ return;
+ }
+
+ if (!eth_addr_from_string(argv[3], &mac)) {
+ unixctl_command_reply_error(conn, "bad MAC address");
+ return;
+ }
+ if (!xlate_delete_static_mac_entry(ofproto, mac, vlan)) {
+ unixctl_command_reply_error(conn, "could not find static mac entry\n");
+ } else {
+ unixctl_command_reply(conn, NULL);
+ }
+}
+
+static void
ofproto_unixctl_fdb_stats_clear(struct unixctl_conn *conn, int argc,
const char *argv[], void *aux OVS_UNUSED)
{
@@ -5932,6 +6028,9 @@ ofproto_unixctl_fdb_stats_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
PRIuSIZE"/%"PRIuSIZE"\n",
hmap_count(&ofproto->ml->table), ofproto->ml->max_entries);
ds_put_format(&ds,
+ " Current static MAC entries in the table : %"PRIuSIZE"\n",
+ ofproto->ml->static_entries);
+ ds_put_format(&ds,
" Total number of learned MAC entries : %"PRIu64"\n",
ofproto->ml->total_learned);
ds_put_format(&ds,
@@ -6437,6 +6536,10 @@ ofproto_unixctl_init(void)
}
registered = true;
+ unixctl_command_register("fdb/add", "bridge port vlan mac", 4, 4,
+ ofproto_unixctl_fdb_add, NULL);
+ unixctl_command_register("fdb/del", "bridge vlan mac", 3, 3,
+ ofproto_unixctl_fdb_delete, NULL);
unixctl_command_register("fdb/flush", "[bridge]", 0, 1,
ofproto_unixctl_fdb_flush, NULL);
unixctl_command_register("fdb/show", "bridge", 1, 1,