Introduced functions get_ipvlan_mode() and get_ipvlan_mode_name() to convert between name <-> IPVLAN_MODE_XXX. Next patch will add new mode and inplace code is becoming too large. Signed-off-by: Dmitry Skorodumov --- ip/iplink_ipvlan.c | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/ip/iplink_ipvlan.c b/ip/iplink_ipvlan.c index f29fa4f9..691fd6f3 100644 --- a/ip/iplink_ipvlan.c +++ b/ip/iplink_ipvlan.c @@ -25,6 +25,31 @@ static void print_explain(struct link_util *lu, FILE *f) lu->id); } +static int get_ipvlan_mode(const char *mode) +{ + if (strcmp(mode, "l2") == 0) + return IPVLAN_MODE_L2; + if (strcmp(mode, "l3") == 0) + return IPVLAN_MODE_L3; + if (strcmp(mode, "l3s") == 0) + return IPVLAN_MODE_L3S; + return -1; +} + +static const char *get_ipvlan_mode_name(__u16 mode) +{ + switch (mode) { + case IPVLAN_MODE_L2: + return "l2"; + case IPVLAN_MODE_L3: + return "l3"; + case IPVLAN_MODE_L3S: + return "l3s"; + default: + return "unknown"; + } +} + static int ipvlan_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { @@ -33,21 +58,17 @@ static int ipvlan_parse_opt(struct link_util *lu, int argc, char **argv, while (argc > 0) { if (matches(*argv, "mode") == 0) { - __u16 mode = 0; + int mode; NEXT_ARG(); - if (strcmp(*argv, "l2") == 0) - mode = IPVLAN_MODE_L2; - else if (strcmp(*argv, "l3") == 0) - mode = IPVLAN_MODE_L3; - else if (strcmp(*argv, "l3s") == 0) - mode = IPVLAN_MODE_L3S; - else { - fprintf(stderr, "Error: argument of \"mode\" must be either \"l2\", \"l3\" or \"l3s\"\n"); + mode = get_ipvlan_mode(*argv); + if (mode < 0) { + fprintf(stderr, "Error: argument of \"mode\" must be either " + "\"l2\", \"l3\" or \"l3s\"\n"); return -1; } - addattr16(n, 1024, IFLA_IPVLAN_MODE, mode); + addattr16(n, 1024, IFLA_IPVLAN_MODE, (__u16)mode); } else if (matches(*argv, "private") == 0 && !mflag_given) { flags |= IPVLAN_F_PRIVATE; mflag_given = true; @@ -82,9 +103,7 @@ static void ipvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_IPVLAN_MODE]) { if (RTA_PAYLOAD(tb[IFLA_IPVLAN_MODE]) == sizeof(__u16)) { __u16 mode = rta_getattr_u16(tb[IFLA_IPVLAN_MODE]); - const char *mode_str = mode == IPVLAN_MODE_L2 ? "l2" : - mode == IPVLAN_MODE_L3 ? "l3" : - mode == IPVLAN_MODE_L3S ? "l3s" : "unknown"; + const char *mode_str = get_ipvlan_mode_name(mode); print_string(PRINT_ANY, "mode", " mode %s ", mode_str); } -- 2.25.1 A small section about ipvlan/ipvtap link types. Most of the phrases are taken from Documentation/networking/ipvlan.rst Signed-off-by: Dmitry Skorodumov --- man/man8/ip-link.8.in | 56 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index ef45fe08..def83184 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -1652,6 +1652,62 @@ a multicast address will be queued as broadcast if the number of devices using it is greater than the given value. .in -8 +.TP +IPVLAN and IPVTAP Type Support +For a link of type +.I IPVLAN +or +.I IPVTAP +the following additional arguments are supported: + +.BI "ip link add link " MASTER " name " SLAVE +.BR type " { " ipvlan " | " ipvtap " } " +.RB " [ " mode " { " l3 " | " l3s " | " l2 " } ] " +.RB " [ { " bridge " | " private " | " vepa " } ] " + +.in +8 +.sp +.BR type " { " ipvlan " | " ipvtap " } " +- specifies the link type to use. +.BR ipvlan " creates just a virtual interface, while " +.BR ipvtap " in addition creates a character device " +.BR /dev/tapX " to be used just like a " tuntap " device." + +.B mode l3 +- Default mode. Layer 3 mode: Packets are routed by the host network stack. Slaves do +not receive multicast or broadcast traffic. Provides stronger isolation +between slaves. + +.B mode l3s +- Very similar to the +.BR l3 +mode except that iptables (conn-tracking) works in this mode +and hence it is L3-symmetric (L3s). + +.B mode l2 +- In this mode TX processing happens on the stack instance attached to the +slave device and packets are switched and queued to the master device to send +out. In this mode the slaves will RX/TX multicast and broadcast (if applicable) +as well. + +.B bridge +- Default option. All endpoints are directly connected to each other, +communication is not redirected through the physical interface's peer. + +.B private +- Do not allow communication between +instances on the same physical interface, even if the external switch supports +hairpin mode. + +.B vepa +- Virtual Ethernet Port Aggregator option. Data from one +instance to the other on the same physical interface is transmitted over the +physical interface. Either the attached switch needs to support hairpin mode, +or there must be a TCP/IP router forwarding the packets in order to allow +communication. + +.in -8 + .TP High-availability Seamless Redundancy (HSR) Support For a link of type -- 2.25.1 Supported mode l2macnat for ip add link type ipvlan/ipvtap Mode was also described in man-page. Signed-off-by: Dmitry Skorodumov --- include/uapi/linux/if_link.h | 1 + ip/iplink_ipvlan.c | 8 ++++++-- man/man8/ip-link.8.in | 11 ++++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index d05f5cc7..e17e684d 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -1267,6 +1267,7 @@ enum ipvlan_mode { IPVLAN_MODE_L2 = 0, IPVLAN_MODE_L3, IPVLAN_MODE_L3S, + IPVLAN_MODE_L2_MACNAT, IPVLAN_MODE_MAX }; diff --git a/ip/iplink_ipvlan.c b/ip/iplink_ipvlan.c index 691fd6f3..b80ab19b 100644 --- a/ip/iplink_ipvlan.c +++ b/ip/iplink_ipvlan.c @@ -19,7 +19,7 @@ static void print_explain(struct link_util *lu, FILE *f) fprintf(f, "Usage: ... %s [ mode MODE ] [ FLAGS ]\n" "\n" - "MODE: l3 | l3s | l2\n" + "MODE: l3 | l3s | l2 | l2macnat\n" "FLAGS: bridge | private | vepa\n" "(first values are the defaults if nothing is specified).\n", lu->id); @@ -29,6 +29,8 @@ static int get_ipvlan_mode(const char *mode) { if (strcmp(mode, "l2") == 0) return IPVLAN_MODE_L2; + if (strcmp(mode, "l2macnat") == 0) + return IPVLAN_MODE_L2_MACNAT; if (strcmp(mode, "l3") == 0) return IPVLAN_MODE_L3; if (strcmp(mode, "l3s") == 0) @@ -41,6 +43,8 @@ static const char *get_ipvlan_mode_name(__u16 mode) switch (mode) { case IPVLAN_MODE_L2: return "l2"; + case IPVLAN_MODE_L2_MACNAT: + return "l2macnat"; case IPVLAN_MODE_L3: return "l3"; case IPVLAN_MODE_L3S: @@ -65,7 +69,7 @@ static int ipvlan_parse_opt(struct link_util *lu, int argc, char **argv, mode = get_ipvlan_mode(*argv); if (mode < 0) { fprintf(stderr, "Error: argument of \"mode\" must be either " - "\"l2\", \"l3\" or \"l3s\"\n"); + "\"l2\", \"l2macnat\", \"l3\" or \"l3s\"\n"); return -1; } addattr16(n, 1024, IFLA_IPVLAN_MODE, (__u16)mode); diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index def83184..28fa2f7a 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -1662,7 +1662,7 @@ the following additional arguments are supported: .BI "ip link add link " MASTER " name " SLAVE .BR type " { " ipvlan " | " ipvtap " } " -.RB " [ " mode " { " l3 " | " l3s " | " l2 " } ] " +.RB " [ " mode " { " l3 " | " l3s " | " l2 " | " l2macnat " } ] " .RB " [ { " bridge " | " private " | " vepa " } ] " .in +8 @@ -1690,6 +1690,15 @@ slave device and packets are switched and queued to the master device to send out. In this mode the slaves will RX/TX multicast and broadcast (if applicable) as well. +.B mode l2macnat +- This mode extends the L2 mode and is primarily designed for desktop virtual +machines that need to bridge to wireless interfaces. In standard L2 mode, +you must configure IP addresses on slave interfaces to enable frame +multiplexing between slaves and the master. In +.BR l2macnat +mode, IPVLAN automatically learns IPv4/IPv6 and MAC addresses +from outgoing packets. + .B bridge - Default option. All endpoints are directly connected to each other, communication is not redirected through the physical interface's peer. -- 2.25.1