|
25 | 25 | #include "dp-packet.h" |
26 | 26 | #include "ovs-atomic.h" |
27 | 27 | #include "packets.h" |
| 28 | +#include "openvswitch/ofp-parse.h" |
28 | 29 | #include "openvswitch/poll-loop.h" |
29 | 30 | #include "seq.h" |
30 | 31 | #include "openvswitch/shash.h" |
@@ -168,6 +169,7 @@ static bool member_may_enable__(struct member *) OVS_REQUIRES(mutex); |
168 | 169 |
|
169 | 170 | static unixctl_cb_func lacp_unixctl_show; |
170 | 171 | static unixctl_cb_func lacp_unixctl_show_stats; |
| 172 | +static unixctl_cb_func lacp_unixctl_set; |
171 | 173 |
|
172 | 174 | /* Populates 'pdu' with a LACP PDU comprised of 'actor' and 'partner'. */ |
173 | 175 | static void |
@@ -229,6 +231,8 @@ lacp_init(void) |
229 | 231 | lacp_unixctl_show, NULL); |
230 | 232 | unixctl_command_register("lacp/show-stats", "[port]", 0, 1, |
231 | 233 | lacp_unixctl_show_stats, NULL); |
| 234 | + unixctl_command_register("lacp/set", "[port]", 3, INT_MAX, |
| 235 | + lacp_unixctl_set, NULL); |
232 | 236 | } |
233 | 237 |
|
234 | 238 | static void |
@@ -940,6 +944,34 @@ lacp_find(const char *name) OVS_REQUIRES(mutex) |
940 | 944 | return NULL; |
941 | 945 | } |
942 | 946 |
|
| 947 | +static struct member * |
| 948 | +lacp_member_find(struct lacp *lacp, const char *name) OVS_REQUIRES(mutex) |
| 949 | +{ |
| 950 | + struct member *member; |
| 951 | + |
| 952 | + HMAP_FOR_EACH_SAFE (member, node, &lacp->members) { |
| 953 | + if (!strcmp(member->name, name)) { |
| 954 | + return member; |
| 955 | + } |
| 956 | + } |
| 957 | + |
| 958 | + return NULL; |
| 959 | +} |
| 960 | + |
| 961 | +static struct member * |
| 962 | +lacp_member_find_by_key(struct lacp *lacp, uint16_t key) OVS_REQUIRES(mutex) |
| 963 | +{ |
| 964 | + struct member *member; |
| 965 | + |
| 966 | + HMAP_FOR_EACH_SAFE (member, node, &lacp->members) { |
| 967 | + if (member->port_id == key) { |
| 968 | + return member; |
| 969 | + } |
| 970 | + } |
| 971 | + |
| 972 | + return NULL; |
| 973 | +} |
| 974 | + |
943 | 975 | static void |
944 | 976 | ds_put_lacp_state(struct ds *ds, uint8_t state) |
945 | 977 | { |
@@ -1219,5 +1251,245 @@ lacp_get_member_stats(const struct lacp *lacp, const void *member_, |
1219 | 1251 | } |
1220 | 1252 | ovs_mutex_unlock(&mutex); |
1221 | 1253 | return ret; |
| 1254 | +} |
| 1255 | + |
| 1256 | +static void |
| 1257 | +lacp_port_set(struct unixctl_conn *conn, struct lacp *lacp, const char *parms) |
| 1258 | + OVS_REQUIRES(mutex) |
| 1259 | +{ |
| 1260 | + char *value; |
| 1261 | + char *key; |
| 1262 | + char **p = (char **)&parms; |
| 1263 | + while (ofputil_parse_key_value(p, &key, &value)) { |
| 1264 | + lacp->update = false; |
| 1265 | + uint32_t tmp; |
| 1266 | + if (nullable_string_is_equal(key, "status")) { |
| 1267 | + if (strstr(value, "active")) { |
| 1268 | + lacp->active = true; |
| 1269 | + } |
| 1270 | + if (strstr(value, "negotiated")) { |
| 1271 | + lacp->negotiated = true; |
| 1272 | + } |
| 1273 | + |
| 1274 | + } else if (nullable_string_is_equal(key, "sys_id")) { |
| 1275 | + if (!eth_addr_from_string(value, &lacp->sys_id)) { |
| 1276 | + unixctl_command_reply_error(conn, "invalid port sys_id"); |
| 1277 | + return; |
| 1278 | + } |
| 1279 | + } else if (nullable_string_is_equal(key, "sys_priority")) { |
| 1280 | + if (!str_to_uint(value, 10, &tmp)) { |
| 1281 | + unixctl_command_reply_error(conn, "invalid port sys_prority"); |
| 1282 | + return; |
| 1283 | + } |
| 1284 | + lacp->sys_priority = tmp; |
| 1285 | + } else if (nullable_string_is_equal(key, "key")) { |
| 1286 | + if (!str_to_uint(value, 10, &tmp)) { |
| 1287 | + unixctl_command_reply_error(conn, "invalid port key"); |
| 1288 | + return; |
| 1289 | + } |
| 1290 | + lacp->key_member = lacp_member_find_by_key(lacp, tmp); |
| 1291 | + } |
| 1292 | + } |
| 1293 | +} |
| 1294 | + |
| 1295 | +static uint8_t |
| 1296 | +lacp_state_from_str(const char *s) |
| 1297 | +{ |
| 1298 | + uint8_t state = 0; |
| 1299 | + if (strstr(s, "activity")) { |
| 1300 | + state |= LACP_STATE_ACT; |
| 1301 | + } |
| 1302 | + if (strstr(s, "timeout")) { |
| 1303 | + state |= LACP_STATE_TIME; |
| 1304 | + } |
| 1305 | + if (strstr(s, "aggregation")) { |
| 1306 | + state |= LACP_STATE_AGG; |
| 1307 | + } |
| 1308 | + if (strstr(s, "synchronized")) { |
| 1309 | + state |= LACP_STATE_SYNC; |
| 1310 | + } |
| 1311 | + if (strstr(s, "collecting")) { |
| 1312 | + state |= LACP_STATE_COL; |
| 1313 | + } |
| 1314 | + if (strstr(s, "distributing")) { |
| 1315 | + state |= LACP_STATE_DIST; |
| 1316 | + } |
| 1317 | + if (strstr(s, "defaulted")) { |
| 1318 | + state |= LACP_STATE_DEF; |
| 1319 | + } |
| 1320 | + if (strstr(s, "expired")) { |
| 1321 | + state |= LACP_STATE_EXP; |
| 1322 | + } |
| 1323 | + return state; |
| 1324 | +} |
1222 | 1325 |
|
| 1326 | +static void |
| 1327 | +lacp_member_set(struct unixctl_conn *conn, struct member *member, |
| 1328 | + const char *op, const char *parms) OVS_REQUIRES(mutex) |
| 1329 | +{ |
| 1330 | + char *value; |
| 1331 | + char *key; |
| 1332 | + char **p = (char **)&parms; |
| 1333 | + if (nullable_string_is_equal(op, "member")) { |
| 1334 | + while (ofputil_parse_key_value(p, &key, &value)) { |
| 1335 | + uint32_t tmp; |
| 1336 | + if (nullable_string_is_equal(key, "port_id")) { |
| 1337 | + if (!str_to_uint(value, 10, &tmp)) { |
| 1338 | + unixctl_command_reply_error(conn, "invalid member " |
| 1339 | + "port_id"); |
| 1340 | + return; |
| 1341 | + } |
| 1342 | + member->port_id = tmp; |
| 1343 | + } else if (nullable_string_is_equal(key, "port_priority")) { |
| 1344 | + if (!str_to_uint(value, 10, &tmp)) { |
| 1345 | + unixctl_command_reply_error(conn, "invalid member " |
| 1346 | + "port_priority"); |
| 1347 | + return; |
| 1348 | + } |
| 1349 | + member->port_priority = tmp; |
| 1350 | + } else if (nullable_string_is_equal(key, "status")) { |
| 1351 | + if (strstr(value, "current")) { |
| 1352 | + member->status = LACP_CURRENT; |
| 1353 | + member->carrier_up = true; |
| 1354 | + } else if (strstr(value, "expired")) { |
| 1355 | + member->status = LACP_EXPIRED; |
| 1356 | + } else if (strstr(value, "defaulted")) { |
| 1357 | + member->status = LACP_DEFAULTED; |
| 1358 | + } |
| 1359 | + |
| 1360 | + if (strstr(value, "attached")) { |
| 1361 | + member->attached = true; |
| 1362 | + } |
| 1363 | + } |
| 1364 | + } |
| 1365 | + } else if (nullable_string_is_equal(op, "actor")) { |
| 1366 | + while (ofputil_parse_key_value(p, &key, &value)) { |
| 1367 | + uint32_t tmp; |
| 1368 | + if (nullable_string_is_equal(key, "sys_id")) { |
| 1369 | + struct eth_addr addr; |
| 1370 | + if (!eth_addr_from_string(value, &addr)) { |
| 1371 | + unixctl_command_reply_error(conn, "invalid member " |
| 1372 | + "actor sys_id"); |
| 1373 | + return; |
| 1374 | + } |
| 1375 | + member->ntt_actor.sys_id = addr; |
| 1376 | + } else if (nullable_string_is_equal(key, "sys_priority")) { |
| 1377 | + if (!str_to_uint(value, 10, &tmp)) { |
| 1378 | + unixctl_command_reply_error(conn, "invalid member " |
| 1379 | + "actor sys_priority"); |
| 1380 | + return; |
| 1381 | + } |
| 1382 | + member->ntt_actor.sys_priority = htons(tmp); |
| 1383 | + } else if (nullable_string_is_equal(key, "port_id")) { |
| 1384 | + if (!str_to_uint(value, 10, &tmp)) { |
| 1385 | + unixctl_command_reply_error(conn, "invalid member " |
| 1386 | + "actor port_id"); |
| 1387 | + return; |
| 1388 | + } |
| 1389 | + member->ntt_actor.port_id = htons(tmp); |
| 1390 | + } else if (nullable_string_is_equal(key, "port_priority")) { |
| 1391 | + if (!str_to_uint(value, 10, &tmp)) { |
| 1392 | + unixctl_command_reply_error(conn, "invalid member " |
| 1393 | + "actor port_priority"); |
| 1394 | + return; |
| 1395 | + } |
| 1396 | + member->ntt_actor.port_priority = htons(tmp); |
| 1397 | + } else if (nullable_string_is_equal(key, "key")) { |
| 1398 | + if (!str_to_uint(value, 10, &tmp)) { |
| 1399 | + unixctl_command_reply_error(conn, "invalid member " |
| 1400 | + "actor key"); |
| 1401 | + return; |
| 1402 | + } |
| 1403 | + member->ntt_actor.key = htons(tmp); |
| 1404 | + } else if (nullable_string_is_equal(key, "state")) { |
| 1405 | + member->ntt_actor.state = lacp_state_from_str(value); |
| 1406 | + VLOG_INFO("member->ntt_actor.state (%p) (%d)", |
| 1407 | + &(member->ntt_actor.state), member->ntt_actor.state); |
| 1408 | + } |
| 1409 | + } |
| 1410 | + } else if (nullable_string_is_equal(op, "partner")) { |
| 1411 | + while (ofputil_parse_key_value(p, &key, &value)) { |
| 1412 | + uint32_t tmp; |
| 1413 | + if (nullable_string_is_equal(key, "sys_id")) { |
| 1414 | + struct eth_addr addr; |
| 1415 | + if (!eth_addr_from_string(value, &addr)) { |
| 1416 | + unixctl_command_reply_error(conn, "invalid member " |
| 1417 | + "partner sys_id"); |
| 1418 | + return; |
| 1419 | + } |
| 1420 | + member->partner.sys_id = addr; |
| 1421 | + } else if (nullable_string_is_equal(key, "sys_priority")) { |
| 1422 | + if (!str_to_uint(value, 10, &tmp)) { |
| 1423 | + unixctl_command_reply_error(conn, "invalid member " |
| 1424 | + "partner sys_priority"); |
| 1425 | + return; |
| 1426 | + } |
| 1427 | + member->partner.sys_priority = htons(tmp); |
| 1428 | + } else if (nullable_string_is_equal(key, "port_id")) { |
| 1429 | + if (!str_to_uint(value, 10, &tmp)) { |
| 1430 | + unixctl_command_reply_error(conn, "invalid member " |
| 1431 | + "partner port_id"); |
| 1432 | + return; |
| 1433 | + } |
| 1434 | + member->partner.port_id = htons(tmp); |
| 1435 | + } else if (nullable_string_is_equal(key, "port_priority")) { |
| 1436 | + if (!str_to_uint(value, 10, &tmp)) { |
| 1437 | + unixctl_command_reply_error(conn, "invalid member " |
| 1438 | + "partner port_priority"); |
| 1439 | + return; |
| 1440 | + } |
| 1441 | + member->partner.port_priority = htons(tmp); |
| 1442 | + } else if (nullable_string_is_equal(key, "key")) { |
| 1443 | + if (!str_to_uint(value, 10, &tmp)) { |
| 1444 | + unixctl_command_reply_error(conn, "invalid member " |
| 1445 | + "partner key"); |
| 1446 | + return; |
| 1447 | + } |
| 1448 | + member->partner.key = htons(tmp); |
| 1449 | + } else if (nullable_string_is_equal(key, "state")) { |
| 1450 | + member->partner.state = lacp_state_from_str(value); |
| 1451 | + } |
| 1452 | + } |
| 1453 | + } else { |
| 1454 | + unixctl_command_reply_error(conn, "invalid member op"); |
| 1455 | + } |
| 1456 | + timer_set_duration(&member->tx, LACP_FAST_TIME_TX); |
| 1457 | + timer_set_duration(&member->rx, LACP_FAST_TIME_TX); |
| 1458 | +} |
| 1459 | + |
| 1460 | +static void |
| 1461 | +lacp_unixctl_set(struct unixctl_conn *conn, int argc, const char *argv[], |
| 1462 | + void *aux OVS_UNUSED) OVS_EXCLUDED(mutex) |
| 1463 | +{ |
| 1464 | + struct member *member; |
| 1465 | + struct lacp *lacp; |
| 1466 | + |
| 1467 | + lacp_lock(); |
| 1468 | + lacp = lacp_find(argv[1]); |
| 1469 | + if (!lacp) { |
| 1470 | + unixctl_command_reply_error(conn, "lacp port not found"); |
| 1471 | + goto out; |
| 1472 | + } |
| 1473 | + |
| 1474 | + if (nullable_string_is_equal(argv[2], "port")) { |
| 1475 | + lacp_port_set(conn, lacp, argv[3]); |
| 1476 | + } else if (nullable_string_is_equal(argv[2], "member")) { |
| 1477 | + member = lacp_member_find(lacp, argv[3]); |
| 1478 | + if (!member) { |
| 1479 | + unixctl_command_reply_error(conn, "lacp member not found"); |
| 1480 | + goto out; |
| 1481 | + } |
| 1482 | + if (argc < 5) { |
| 1483 | + unixctl_command_reply_error(conn, "invalid member parms"); |
| 1484 | + goto out; |
| 1485 | + } |
| 1486 | + lacp_member_set(conn, member, argv[4], argv[5]); |
| 1487 | + } else { |
| 1488 | + unixctl_command_reply_error(conn, "invalid op type"); |
| 1489 | + goto out; |
| 1490 | + } |
| 1491 | + |
| 1492 | +out: |
| 1493 | + unixctl_command_reply(conn, NULL); |
| 1494 | + lacp_unlock(); |
1223 | 1495 | } |
0 commit comments