Skip to content

Commit 1f11532

Browse files
[PCD-4934] Add l2only mac spoofing prevention, and prevent flooding for east-west l2only traffic (#13)
* access pf9-allow-mac-forged-transmits option * add mac_spoofing prevention for all ports having port_security disabled. * make it l2_port only * Get src mac from neutron for this special case * add l2only mac spoofing prevention * add multicast check * removr logs * remove eth dst flow and add validation for p9-src-mac field --------- Co-authored-by: Kshitij <kshitij@platform9.com>
1 parent de2407f commit 1f11532

1 file changed

Lines changed: 77 additions & 2 deletions

File tree

northd/northd.c

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8233,6 +8233,70 @@ add_l2only_flood_all(struct ovn_port *p, struct hmap *lflows)
82338233
ds_destroy(&match);
82348234
}
82358235

8236+
/* Allow VIF traffic if and only if eth.src matches the port MAC.
8237+
* This preserves MAC anti-spoofing while realxing IP/ARP restrictions.
8238+
*/
8239+
static void
8240+
add_l2only_mac_spoofing_prevention(struct ovn_port *p, struct hmap *lflows, const char* src_mac){
8241+
if (!p || !p->od || !p->nbsp) {
8242+
VLOG_DBG("port is null, skipping...");
8243+
return;
8244+
}
8245+
8246+
if (!port_is_l2_only_port(p)) {
8247+
return;
8248+
}
8249+
8250+
struct ds match = DS_EMPTY_INITIALIZER;
8251+
struct ds action = DS_EMPTY_INITIALIZER;
8252+
8253+
/* Use src_mac as the allowed MAC set for this VIF. */
8254+
VLOG_DBG("Adding mac_spoofing prevention to port %s, mac_address: %s", p->key, src_mac);
8255+
8256+
struct eth_addr ea;
8257+
if (eth_addr_from_string(src_mac, &ea)) {
8258+
ds_clear(&match);
8259+
ds_clear(&action);
8260+
ds_put_format(&match, "inport == \"%s\" && eth.src != %s", p->key, src_mac);
8261+
ds_put_format(&action, "%s=1; next;", REGBIT_PORT_SEC_DROP);
8262+
ovn_lflow_add_with_hint(
8263+
lflows, p->od,
8264+
S_SWITCH_IN_CHECK_PORT_SEC,
8265+
110, /* higher than minimal_portsec_bypass rules */
8266+
ds_cstr(&match),
8267+
ds_cstr(&action),
8268+
&p->nbsp->header_, NULL
8269+
);
8270+
8271+
/* ARP: ensure arp.sha matches MAC */
8272+
ds_clear(&match);
8273+
ds_put_format(&match, "inport == \"%s\" && eth.type == 0x0806 && arp.sha != %s", p->key, src_mac);
8274+
ovn_lflow_add_with_hint(lflows, p->od,
8275+
S_SWITCH_IN_CHECK_PORT_SEC,
8276+
110, /* higher than minimal_portsec_bypass rules */
8277+
ds_cstr(&match),
8278+
ds_cstr(&action),
8279+
&p->nbsp->header_, NULL
8280+
);
8281+
8282+
/* Drop wherever REGBIT_PORT_SEC_DROP=1 with a higher priority than minimal_portsec_bypass */
8283+
ds_clear(&match);
8284+
ds_put_format(&match, "inport == \"%s\" && %s == 1", p->key, REGBIT_PORT_SEC_DROP);
8285+
ovn_lflow_add_with_hint(lflows, p->od,
8286+
S_SWITCH_IN_APPLY_PORT_SEC,
8287+
110, /* higher than minimal_portsec_bypass rules */
8288+
ds_cstr(&match),
8289+
debug_drop_action(),
8290+
&p->nbsp->header_, NULL
8291+
);
8292+
}else {
8293+
VLOG_WARN("invalid mac_address: %s for port %s, skipping mac spoofing prevention...", src_mac, p->key);
8294+
}
8295+
8296+
ds_destroy(&match);
8297+
ds_destroy(&action);
8298+
}
8299+
82368300
/* Minimal and scoped port-security bypass for L2-only VIFs.
82378301
* - Only affects this single VIF.
82388302
* - Keeps stage ordering intact (still runs later stages).
@@ -16097,7 +16161,6 @@ build_lswitch_and_lrouter_flows(
1609716161
const struct chassis_features *features,
1609816162
const char *svc_monitor_mac)
1609916163
{
16100-
1610116164
char *svc_check_match = xasprintf("eth.dst == %s", svc_monitor_mac);
1610216165

1610316166
if (parallelization_state == STATE_USE_PARALLELIZATION) {
@@ -16211,18 +16274,30 @@ build_lswitch_and_lrouter_flows(
1621116274
*
1621216275
* Both are low/specific priority so the standard pipeline keeps
1621316276
* taking precedence when applicable. */
16277+
VLOG_DBG("processing l2_only ports...");
1621416278
HMAP_FOR_EACH (op, key_node, lsi.ls_ports) {
1621516279
if (!op || !op->od || !op->nbsp) {
16280+
VLOG_DBG("port is null, skipping.");
1621616281
continue;
1621716282
}
1621816283
if (!port_is_l2_only_port(op)) {
16284+
VLOG_DBG("port is not l2_only, skipping.");
1621916285
continue;
1622016286
}
1622116287

16222-
VLOG_INFO("L2-only VIF detected on %s; adding port-sec bypass + uu fallback",
16288+
VLOG_DBG("L2-only VIF detected on %s; adding port-sec bypass + uu fallback",
1622316289
op->json_key);
16290+
16291+
bool allow_forged_mac = smap_get_bool(&op->nbsp->external_ids, "pf9-allow-mac-forged-transmits", false);
16292+
char *src_mac = smap_get_def(&op->nbsp->external_ids, "pf9-l2port-src-mac", "");
16293+
16294+
VLOG_DBG("port: %s; src_mac: %s; allow_forged_mac: %s", op->key, src_mac, allow_forged_mac ? "true" : "false");
16295+
1622416296
add_minimal_portsec_bypass(op, lsi.lflows);
1622516297
add_l2only_flood_all(op, lsi.lflows);
16298+
if (!allow_forged_mac && src_mac && src_mac[0]) {
16299+
add_l2only_mac_spoofing_prevention(op, lflows, src_mac);
16300+
}
1622616301
}
1622716302
stopwatch_stop(LFLOWS_PORTS_STOPWATCH_NAME, time_msec());
1622816303
/* PF9 stop */

0 commit comments

Comments
 (0)