Памятка на тему IPv6 и плагинов к ModemManager
Получение IPv4 (singlestack) плагином MM (дабы ближе к теме - плагин Huawei для cdc_ncm модемов) выглядит следующим образом:
0. (cdc-wdm0): --> 'AT^NDISDUP=1,0<CR><LF>'
(для предсказуемости исходного состояния соединения - начинаем с отправки дисконнект).
(cdc-wdm0): --> 'AT^NDISDUP=1,1,"apn"<CR><LF>'
отправляем коннект.(cdc-wdm0): --> 'AT^NDISSTATQRY?<CR><LF>'
- в цикле до 60сек, пока не получим ^NDISSTATQRY: 1,,,"IPV4",0,,,"IPV6" (подключено по IPv4). Если не получим за 60сек - вернем ошибку и дальше пусть решает NetworkManager, дергать интерфейс повторно или нет.
Вообще-то, в доках к AT командам от Huawei (INet в помощь) указан иной алгоритм получения адреса и совсем иные таймауты:
The command querying the IP address must be run 5s later after dialing command is issued. If not, you should run the command each second again. If the total time is over 15s, it can be considered that the query fails.
но поскольку код плагина написан в т.ч. за авторством Huawei, будем считать что им виднее - чего где писать и сколько ждать).(cdc-wdm0): --> 'AT^DHCP?<CR><LF>'
- запрашиваем IPv4 инфу, по результату отклика:
3a.(cdc-wdm0): <-- '^DHCP: <clip>,<netmask>,<gate>,<dhcp>,<pDNS>,<sDNS>...'
- заполняем конфу (ip/netmask, gateway, dns) результатами ответа и выставляем флаг method=MM_BEARER_IP_METHOD_STATIC.
! Ключевой момент - для NetworkManager-а, которому из MM будет передана конфигурация интерфейса, настройки являются статическими - NM не запускает dhclient для этого интерфейса (поле method в конфигурации интерфейса в NM при этом игнорируется).
А вот в случае реализации IPv6 для плагина Huawei MM (которой в природе отродясь не бывало, и по мотивам написания которого этот опус и родился), все становится гораздо сложнее (для других реализаций по-проще - об этом ниже):
0. (cdc-wdm0): --> 'AT^NDISDUP=1,0<CR><LF>'
(для предсказуемости исходного состояния соединения - начинаем с отправки дисконнект).
(cdc-wdm0): --> 'AT^NDISDUP=1,1,"apn"<CR><LF>'
- отправляем коннект.(cdc-wdm0): --> 'AT^NDISSTATQRY?<CR><LF>'
- в цикле до 60сек, пока не получим... Оп-па! А что мы получим? Поехали по шагам: 2a. способность работы модема с IPv6 можно определить через "AT^IPV6CAP?". Допустим определили - если1
(IPv4 only), все придумано до нас.2
(IPv6 only) - чуть модифицируем предыдущий пункт и вперед.7
(предыдущие два варианта + IPv4v6) - вот это веселее. Его и рассмотрим: "^NDISSTATQRY?" для dualstack подключения должен вернуть^NDISSTATQRY: 1,,,"IPV4",1,,,"IPV6"
. А вот вернет ли, зависит от нескольких факторов, не зависящих (каламбур) от нас и нашего желания:
- плохая связь (на это и заложен вышеупомянутый цикл 60сек). Флаги в отклике ^NDISSTATQRY для IPv4 и IPv6 устанавливаются не одновременно. Чем хуже связь, тем больше может оказаться промежуток между получением
^NDISSTATQRY: 1,,,"IPV4",0,,,"IPV6"
(или^NDISSTATQRY: 0,,,"IPV4",1,,,"IPV6"
) и^NDISSTATQRY: 1,,,"IPV4",1,,,"IPV6"
. В печальном случае 59сек до IPv4 (или, соответственно, IPv6), а IPv6 (или, соответственно, IPv4) вообще не дождемся. - а самое печальное, это то, что наличие IPv6 в dualstack - это, так сказать, опция провайдера - выдает он его или нет - програмно не определить. Если не выдает, в приведенном сценарии мы будем поднимать коннект 59сек (получили IPv4 но ждем IPv6). Всегда. Ну или экстраполировать таймаут получение IP одного семейства из времени получения другого - к примеру, пришел IPv4 за 3сек (от момента завершения этапа 1) - связь хорошая, ждем IPv6 не более +6сек...
Правда опции провайдера знает абонент - т.е. можно заранее рубануть IPv6 в модеме через NVRAM, если оператор не IPv6-capable. Очень удобный и универсальный способ, ага...
В других модемах (не Huawei) вопрос решается проще, поскольку и IPv4, и IPv6 возвращаются одной командой. Пришли оба - dualstack. Пришел один - single. Но Huawei простым путем не пошел (хотя в доках к AT командам от Huawei, к команде '^DHCP? 'сказано: "This command does not currently support IPv6 address lookup, follow-up will extend the command.", так что в дальнейшем возможно станет по-проще, но пока оно все еще follow-up).
(cdc-wdm0): --> 'AT^DHCP?<CR><LF>'
- запрашиваем IPv4 инфу...
3a. ...Все как в singlestack варианте.(cdc-wdm0): --> 'AT^DHCPV6?<CR><LF>'
- запрашиваем IPv6 инфу...
4a.(cdc-wdm0): <-- ^DHCPV6:<clip_v6>,<netmask_v6>,<gate_v6>,<dhcp_v6>,<pDNS_v6>,<sDNS_v6>...'
- почти как в singlestack варианте, вот только gateway и netmask обычно не заполнены (в каментах к коду других плагинов упоминают, что и dns может не быть). Для получения недостающей инфы нужно обратиться к SLAAC - он вернет всю информацию (ip/netmask, gateway). DNS в общем случае не вернет (есть RFC 5006/6106, но не всегда и не у всех). Так что прописываем в конфу адрес из AT^DHCPV6?, ручками ставим префикс /64 (поскольку он тоже не возвращается), прописываем DNS и выставляем method=MM_BEARER_IP_METHOD_DHCP.
! Ключевой момент - NetworkManager должен запустить SLAAC и stateless DHCPv6 запрос для интерфейса (SLAAC для получения gateway, DHCPv6 - для DNS).- Лирическое отступление:
SLAAC для получения gateway, stateless DHCPv6 - для DNS, было изначально задумано при разработке IPv6. Потом выяснилось, что неудобно (ну или просто кого-то торкнуло) - и придумали "IPv6 Router Advertisement Option for DNS Configuration" - RFC 5006 (obsoleted by RFC 6106). Заранее, ясное дело, не известно - кто что из задуманного реализовал/использует в конкретном случае (как на клиенте, так и у оператора): - NetworkManager, к примеру, использует SLAAC для получения gateway и stateless DHCPv6 - для DNS. Для этого даже генерит link-local ipv6 адрес (не из MAC, который у всех E3372 одинаковый и корявый - используется методика из RFC7217). RFC 5006/6106 не использует.
- А вот сотовые операторы обычно передают DNS только на канальном уровне - поэтому нужно в плагине MM его подцепить и прописать (на этапе 3a) - потом будет поздно. Ненормальной эту ситуацию не назовешь - в IPv4 для PPP-образных каналов было все то-же самое - gateway и DNS передавались в процессе LCP/IPCP-согласования (RFC не указываю - там их как грязи) - никто DHCPv4 для этого не поднимал. Но думаю, к моменту массового внедрения IPv6, вариантов получения DNS будет больше десятка... (грустный юмор такой, если что :-( )
- Лирическое отступление:
! Может так случиться, что модем вернет IPv6 Link-Local адрес - его нужно назначить интерфейсу перед выполнением SLAAC, поскольку мобильная сеть может ожидать, что настройка SLAAC будет использовать именно этот адрес (это из доки к ModemManager). В этом случае global адрес будет так-же получен по SLAAC. Т.е. возвращенный адрес должен быть прописан на интерфейсе ибо может понадобиться DHCPv6 серверу оператора.
З.Ы.: Ну вот и дополнительный сюрприз - откуда не ждали... В CentOS 7 NetworkManager не поднимает link-local адрес на интерфейсе, если ModemManager установил global адрес, даже при наличии флага method=MM_BEARER_IP_METHOD_DHCP
(NM 1.12.0-10.el7_6, MM 1.6.10-1.el7). Невзирая на заявление в Release Notes к ModemManager v1.4.0:
** Setting DHCP as IP method in the IPv6 settings means that SLAAC should
be used to retrieve correct addressing and routing details.
** DHCP IP method may now be combined with an explicit static IP address, as
IPv6 SLAAC may require the link-local address to be present.
Нет, ну логика-то примерно понятна - SLAAC не запустится, если на интерфейсе нет link-local адреса, а NetworkManager не будет генерировать link-local адрес для интерфейса, если видит уже установленный на нем global адрес (и вот тут вопрос -
а почему бы и не сгенерировать, если нужно для обеспечения процесса?), даже если от MM пришел метод dhcp... Но вот товарищи, написавшие кучу кода именно с прицелом на описанный выше алгоритм (я с их кода плагин для Huawei и дописывал вообще-то) - они-то свой код тестировали? Т.е. получается (в т.ч. исходя из вышеупомянутых Notes), что еще в ModemManager-е нужно установить (сгенерировать по RFC7217) link-local адрес и прописать его на интерфейс вместе с полученным от оператора DNS? А на адрес, передаваемый оператором забить во всех случаях, кроме случаев когда это link-local адрес?...
Придется перепроверять всю эту кухню на последней fedora - возможно нужен NetworkManager поновее, а я зря на хороших людей поклеп возвожу...