diff options
author | Vasu Dasari <vdasari@gmail.com> | 2021-06-29 16:43:39 -0400 |
---|---|---|
committer | Ilya Maximets <i.maximets@ovn.org> | 2021-07-16 16:21:02 +0200 |
commit | ccc24fc88d590e1d89185ee5650c9c5f031c916d (patch) | |
tree | 6ea6b770f62ed8e163b392a253402edfa058eb05 /ofproto/ofproto-dpif.c | |
parent | ae2424696cff5a8a60db9a961bc366abced77e8d (diff) | |
download | openvswitch-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.c | 111 |
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, |